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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  27  */
  28 
  29 
  30 /*
  31  * usb multi interface and common class driver
  32  *
  33  *      this driver attempts to attach each interface to a driver
  34  *      and may eventually handle common class features such as
  35  *      shared endpoints
  36  */
  37 
  38 #if defined(lint) && !defined(DEBUG)
  39 #define DEBUG   1
  40 #endif
  41 #include <sys/usb/usba/usbai_version.h>
  42 #include <sys/usb/usba.h>
  43 #include <sys/usb/usba/usba_types.h>
  44 #include <sys/usb/usba/usba_impl.h>
  45 #include <sys/usb/usba/usba_ugen.h>
  46 #include <sys/usb/usb_mid/usb_midvar.h>
  47 
  48 void usba_free_evdata(usba_evdata_t *);
  49 
  50 /* Debugging support */
  51 uint_t usb_mid_errlevel = USB_LOG_L4;
  52 uint_t usb_mid_errmask = (uint_t)DPRINT_MASK_ALL;
  53 uint_t usb_mid_instance_debug = (uint_t)-1;
  54 uint_t usb_mid_bus_config_debug = 0;
  55 
  56 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errlevel))
  57 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errmask))
  58 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_instance_debug))
  59 
  60 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
  61 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
  62 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
  63 
  64 /*
  65  * Hotplug support
  66  * Leaf ops (hotplug controls for client devices)
  67  */
  68 static int usb_mid_open(dev_t *, int, int, cred_t *);
  69 static int usb_mid_close(dev_t, int, int, cred_t *);
  70 static int usb_mid_read(dev_t, struct uio *, cred_t *);
  71 static int usb_mid_write(dev_t, struct uio *, cred_t *);
  72 static int usb_mid_poll(dev_t, short, int,  short *,
  73                                         struct pollhead **);
  74 
  75 static struct cb_ops usb_mid_cb_ops = {
  76         usb_mid_open,
  77         usb_mid_close,
  78         nodev,          /* strategy */
  79         nodev,          /* print */
  80         nodev,          /* dump */
  81         usb_mid_read,   /* read */
  82         usb_mid_write,  /* write */
  83         nodev,
  84         nodev,          /* devmap */
  85         nodev,          /* mmap */
  86         nodev,          /* segmap */
  87         usb_mid_poll,   /* poll */
  88         ddi_prop_op,    /* prop_op */
  89         NULL,
  90         D_MP
  91 };
  92 
  93 static int usb_mid_busop_get_eventcookie(dev_info_t *dip,
  94                         dev_info_t *rdip,
  95                         char *eventname,
  96                         ddi_eventcookie_t *cookie);
  97 static int usb_mid_busop_add_eventcall(dev_info_t *dip,
  98                         dev_info_t *rdip,
  99                         ddi_eventcookie_t cookie,
 100                         void (*callback)(dev_info_t *dip,
 101                                 ddi_eventcookie_t cookie, void *arg,
 102                                 void *bus_impldata),
 103                         void *arg, ddi_callback_id_t *cb_id);
 104 static int usb_mid_busop_remove_eventcall(dev_info_t *dip,
 105                         ddi_callback_id_t cb_id);
 106 static int usb_mid_busop_post_event(dev_info_t *dip,
 107                         dev_info_t *rdip,
 108                         ddi_eventcookie_t cookie,
 109                         void *bus_impldata);
 110 static int usb_mid_bus_config(dev_info_t *dip,
 111                         uint_t flag,
 112                         ddi_bus_config_op_t op,
 113                         void *arg,
 114                         dev_info_t **child);
 115 static int usb_mid_bus_unconfig(dev_info_t *dip,
 116                         uint_t flag,
 117                         ddi_bus_config_op_t op,
 118                         void *arg);
 119 
 120 
 121 /*
 122  * autoconfiguration data and routines.
 123  */
 124 static int      usb_mid_info(dev_info_t *, ddi_info_cmd_t,
 125                                 void *, void **);
 126 static int      usb_mid_attach(dev_info_t *, ddi_attach_cmd_t);
 127 static int      usb_mid_detach(dev_info_t *, ddi_detach_cmd_t);
 128 
 129 /* other routines */
 130 static void usb_mid_create_pm_components(dev_info_t *, usb_mid_t *);
 131 static int usb_mid_bus_ctl(dev_info_t *, dev_info_t     *,
 132                                 ddi_ctl_enum_t, void *, void *);
 133 static int usb_mid_power(dev_info_t *, int, int);
 134 static int usb_mid_restore_device_state(dev_info_t *, usb_mid_t *);
 135 static usb_mid_t  *usb_mid_obtain_state(dev_info_t *);
 136 static void usb_mid_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
 137 
 138 /*
 139  * Busops vector
 140  */
 141 static struct bus_ops usb_mid_busops = {
 142         BUSO_REV,
 143         nullbusmap,                     /* bus_map */
 144         NULL,                           /* bus_get_intrspec */
 145         NULL,                           /* bus_add_intrspec */
 146         NULL,                           /* bus_remove_intrspec */
 147         NULL,                           /* XXXX bus_map_fault */
 148         NULL,                           /* bus_dma_map */
 149         ddi_dma_allochdl,
 150         ddi_dma_freehdl,
 151         ddi_dma_bindhdl,
 152         ddi_dma_unbindhdl,
 153         ddi_dma_flush,
 154         ddi_dma_win,
 155         ddi_dma_mctl,                   /* bus_dma_ctl */
 156         usb_mid_bus_ctl,                /* bus_ctl */
 157         ddi_bus_prop_op,                /* bus_prop_op */
 158         usb_mid_busop_get_eventcookie,
 159         usb_mid_busop_add_eventcall,
 160         usb_mid_busop_remove_eventcall,
 161         usb_mid_busop_post_event,       /* bus_post_event */
 162         NULL,                           /* bus_intr_ctl */
 163         usb_mid_bus_config,             /* bus_config */
 164         usb_mid_bus_unconfig,           /* bus_unconfig */
 165         NULL,                           /* bus_fm_init */
 166         NULL,                           /* bus_fm_fini */
 167         NULL,                           /* bus_fm_access_enter */
 168         NULL,                           /* bus_fm_access_exit */
 169         NULL                            /* bus_power */
 170 };
 171 
 172 
 173 static struct dev_ops usb_mid_ops = {
 174         DEVO_REV,               /* devo_rev, */
 175         0,                      /* refcnt  */
 176         usb_mid_info,           /* info */
 177         nulldev,                /* identify */
 178         nulldev,                /* probe */
 179         usb_mid_attach,         /* attach */
 180         usb_mid_detach,         /* detach */
 181         nodev,                  /* reset */
 182         &usb_mid_cb_ops,    /* driver operations */
 183         &usb_mid_busops,    /* bus operations */
 184         usb_mid_power,          /* power */
 185         ddi_quiesce_not_needed,         /* quiesce */
 186 };
 187 
 188 static struct modldrv modldrv = {
 189         &mod_driverops, /* Type of module. This one is a driver */
 190         "USB Multi Interface Driver", /* Name of the module. */
 191         &usb_mid_ops,       /* driver ops */
 192 };
 193 
 194 static struct modlinkage modlinkage = {
 195         MODREV_1, (void *)&modldrv, NULL
 196 };
 197 
 198 #define USB_MID_INITIAL_SOFT_SPACE 4
 199 static  void    *usb_mid_statep;
 200 
 201 
 202 /*
 203  * prototypes
 204  */
 205 static void usb_mid_create_children(usb_mid_t *usb_mid);
 206 static int usb_mid_cleanup(dev_info_t *dip, usb_mid_t   *usb_mid);
 207 
 208 /*
 209  * event definition
 210  */
 211 static ndi_event_definition_t usb_mid_ndi_event_defs[] = {
 212         {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
 213                                                 NDI_EVENT_POST_TO_ALL},
 214         {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
 215                                                 NDI_EVENT_POST_TO_ALL},
 216         {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
 217                                                 NDI_EVENT_POST_TO_ALL},
 218         {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
 219                                                 NDI_EVENT_POST_TO_ALL}
 220 };
 221 
 222 #define USB_MID_N_NDI_EVENTS \
 223         (sizeof (usb_mid_ndi_event_defs) / sizeof (ndi_event_definition_t))
 224 
 225 static  ndi_event_set_t usb_mid_ndi_events = {
 226         NDI_EVENTS_REV1, USB_MID_N_NDI_EVENTS, usb_mid_ndi_event_defs};
 227 
 228 
 229 /*
 230  * standard driver entry points
 231  */
 232 int
 233 _init(void)
 234 {
 235         int rval;
 236 
 237         rval = ddi_soft_state_init(&usb_mid_statep, sizeof (struct usb_mid),
 238             USB_MID_INITIAL_SOFT_SPACE);
 239         if (rval != 0) {
 240                 return (rval);
 241         }
 242 
 243         if ((rval = mod_install(&modlinkage)) != 0) {
 244                 ddi_soft_state_fini(&usb_mid_statep);
 245                 return (rval);
 246         }
 247 
 248         return (rval);
 249 }
 250 
 251 
 252 int
 253 _fini(void)
 254 {
 255         int     rval;
 256 
 257         rval = mod_remove(&modlinkage);
 258 
 259         if (rval) {
 260                 return (rval);
 261         }
 262 
 263         ddi_soft_state_fini(&usb_mid_statep);
 264 
 265         return (rval);
 266 }
 267 
 268 
 269 int
 270 _info(struct modinfo *modinfop)
 271 {
 272         return (mod_info(&modlinkage, modinfop));
 273 }
 274 
 275 
 276 /*ARGSUSED*/
 277 static int
 278 usb_mid_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 279 {
 280         usb_mid_t       *usb_mid;
 281         int             instance =
 282             USB_MID_MINOR_TO_INSTANCE(getminor((dev_t)arg));
 283         int             error = DDI_FAILURE;
 284 
 285         switch (infocmd) {
 286         case DDI_INFO_DEVT2DEVINFO:
 287                 if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
 288                     instance)) != NULL) {
 289                         *result = (void *)usb_mid->mi_dip;
 290                         if (*result != NULL) {
 291                                 error = DDI_SUCCESS;
 292                         }
 293                 } else {
 294                         *result = NULL;
 295                 }
 296                 break;
 297 
 298         case DDI_INFO_DEVT2INSTANCE:
 299                 *result = (void *)(intptr_t)instance;
 300                 error = DDI_SUCCESS;
 301                 break;
 302         default:
 303                 break;
 304         }
 305 
 306         return (error);
 307 }
 308 
 309 
 310 /*
 311  * child  post attach/detach notification
 312  */
 313 static void
 314 usb_mid_post_attach(usb_mid_t *usb_mid, uint8_t ifno, struct attachspec *as)
 315 {
 316         USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
 317             "usb_mid_post_attach: ifno = %d result = %d", ifno, as->result);
 318 
 319         /* if child successfully attached, set power */
 320         if (as->result == DDI_SUCCESS) {
 321                 /*
 322                  * Check if the child created wants to be power managed.
 323                  * If yes, the childs power level gets automatically tracked
 324                  * by DDI_CTLOPS_POWER busctl.
 325                  * If no, we set power of the new child by default
 326                  * to USB_DEV_OS_FULL_PWR. Because we should never suspend.
 327                  */
 328                 mutex_enter(&usb_mid->mi_mutex);
 329                 usb_mid->mi_attach_count++;
 330                 mutex_exit(&usb_mid->mi_mutex);
 331         }
 332 }
 333 
 334 
 335 static void
 336 usb_mid_post_detach(usb_mid_t *usb_mid, uint8_t ifno, struct detachspec *ds)
 337 {
 338         USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
 339             "usb_mid_post_detach: ifno = %d result = %d", ifno, ds->result);
 340 
 341         /*
 342          * if the device is successfully detached,
 343          * mark component as idle
 344          */
 345         if (ds->result == DDI_SUCCESS) {
 346                 usba_device_t *usba_device =
 347                     usba_get_usba_device(usb_mid->mi_dip);
 348 
 349                 mutex_enter(&usb_mid->mi_mutex);
 350 
 351                 /* check for leaks except when where is a ugen open */
 352                 if ((ds->cmd == DDI_DETACH) &&
 353                     (--usb_mid->mi_attach_count == 0) && usba_device &&
 354                     (usb_mid->mi_ugen_open_count == 0)) {
 355                         usba_check_for_leaks(usba_device);
 356                 }
 357                 mutex_exit(&usb_mid->mi_mutex);
 358         }
 359 }
 360 
 361 
 362 /*
 363  * bus ctl support. we handle notifications here and the
 364  * rest goes up to root hub/hcd
 365  */
 366 /*ARGSUSED*/
 367 static int
 368 usb_mid_bus_ctl(dev_info_t *dip,
 369         dev_info_t      *rdip,
 370         ddi_ctl_enum_t  op,
 371         void            *arg,
 372         void            *result)
 373 {
 374         usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
 375         dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
 376         usb_mid_t  *usb_mid;
 377         struct attachspec *as;
 378         struct detachspec *ds;
 379 
 380         usb_mid = usb_mid_obtain_state(dip);
 381 
 382         USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
 383             "usb_mid_bus_ctl:\n\t"
 384             "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
 385             (void *)dip, (void *)rdip, op, arg);
 386 
 387         switch (op) {
 388         case DDI_CTLOPS_ATTACH:
 389                 as = (struct attachspec *)arg;
 390 
 391                 switch (as->when) {
 392                 case DDI_PRE :
 393                         /* nothing to do basically */
 394                         USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
 395                             "DDI_PRE DDI_CTLOPS_ATTACH");
 396                         break;
 397                 case DDI_POST :
 398                         usb_mid_post_attach(usb_mid, usba_get_ifno(rdip),
 399                             (struct attachspec *)arg);
 400                         break;
 401                 }
 402 
 403                 break;
 404         case DDI_CTLOPS_DETACH:
 405                 ds = (struct detachspec *)arg;
 406 
 407                 switch (ds->when) {
 408                 case DDI_PRE :
 409                         /* nothing to do basically */
 410                         USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
 411                             "DDI_PRE DDI_CTLOPS_DETACH");
 412                         break;
 413                 case DDI_POST :
 414                         usb_mid_post_detach(usb_mid, usba_get_ifno(rdip),
 415                             (struct detachspec *)arg);
 416                         break;
 417                 }
 418 
 419                 break;
 420         default:
 421                 /* pass to root hub to handle */
 422                 return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
 423         }
 424 
 425         return (DDI_SUCCESS);
 426 }
 427 
 428 
 429 /*
 430  * bus enumeration entry points
 431  */
 432 static int
 433 usb_mid_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
 434     void *arg, dev_info_t **child)
 435 {
 436         int             rval, circ;
 437         usb_mid_t       *usb_mid = usb_mid_obtain_state(dip);
 438 
 439         USB_DPRINTF_L2(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
 440             "usb_mid_bus_config: op=%d", op);
 441 
 442         if (usb_mid_bus_config_debug) {
 443                 flag |= NDI_DEVI_DEBUG;
 444         }
 445 
 446         ndi_devi_enter(dip, &circ);
 447 
 448         /* enumerate each interface below us */
 449         mutex_enter(&usb_mid->mi_mutex);
 450         usb_mid_create_children(usb_mid);
 451         mutex_exit(&usb_mid->mi_mutex);
 452 
 453         rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
 454         ndi_devi_exit(dip, circ);
 455 
 456         return (rval);
 457 }
 458 
 459 
 460 static int
 461 usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
 462     void *arg)
 463 {
 464         usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
 465 
 466         dev_info_t      *cdip, *mdip;
 467         int             interface, circular_count;
 468         int             rval = NDI_SUCCESS;
 469 
 470         USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
 471             "usb_mid_bus_unconfig: op=%d", op);
 472 
 473         if (usb_mid_bus_config_debug) {
 474                 flag |= NDI_DEVI_DEBUG;
 475         }
 476 
 477         /*
 478          * first offline and if offlining successful, then
 479          * remove children
 480          */
 481         if (op == BUS_UNCONFIG_ALL) {
 482                 flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
 483         }
 484 
 485         ndi_devi_enter(dip, &circular_count);
 486         rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
 487 
 488         if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
 489             (flag & NDI_AUTODETACH) == 0) {
 490                 flag |= NDI_DEVI_REMOVE;
 491                 rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
 492         }
 493 
 494         /* update children's list */
 495         mutex_enter(&usb_mid->mi_mutex);
 496         for (interface = 0; usb_mid->mi_children_dips &&
 497             (interface < usb_mid->mi_n_ifs) &&
 498             (usb_mid->mi_children_ifs[interface]); interface++) {
 499                 mdip = usb_mid->mi_children_dips[interface];
 500 
 501                 /* now search if this dip still exists */
 502                 for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); )
 503                         cdip = ddi_get_next_sibling(cdip);
 504 
 505                 if (cdip != mdip) {
 506                         /* we lost the dip on this interface */
 507                         usb_mid->mi_children_dips[interface] = NULL;
 508                 } else if (cdip) {
 509                         /*
 510                          * keep in DS_INITALIZED to prevent parent
 511                          * from detaching
 512                          */
 513                         (void) ddi_initchild(ddi_get_parent(cdip), cdip);
 514                 }
 515         }
 516         mutex_exit(&usb_mid->mi_mutex);
 517 
 518         ndi_devi_exit(dip, circular_count);
 519 
 520         USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
 521             "usb_mid_bus_config: rval=%d", rval);
 522 
 523         return (rval);
 524 }
 525 
 526 
 527 /* power entry point */
 528 /* ARGSUSED */
 529 static int
 530 usb_mid_power(dev_info_t *dip, int comp, int level)
 531 {
 532         usb_mid_t               *usb_mid;
 533         usb_common_power_t      *midpm;
 534         int                     rval = DDI_FAILURE;
 535 
 536         usb_mid =  usb_mid_obtain_state(dip);
 537 
 538         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
 539             "usb_mid_power: Begin: usb_mid = %p, level = %d",
 540             (void *)usb_mid, level);
 541 
 542         mutex_enter(&usb_mid->mi_mutex);
 543         midpm = usb_mid->mi_pm;
 544 
 545         /* check if we are transitioning to a legal power level */
 546         if (USB_DEV_PWRSTATE_OK(midpm->uc_pwr_states, level)) {
 547                 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
 548                     "usb_mid_power: illegal power level = %d "
 549                     "uc_pwr_states = %x", level, midpm->uc_pwr_states);
 550 
 551                 mutex_exit(&usb_mid->mi_mutex);
 552 
 553                 return (rval);
 554         }
 555 
 556         rval = usba_common_power(dip, &(midpm->uc_current_power),
 557             &(usb_mid->mi_dev_state), level);
 558 
 559         mutex_exit(&usb_mid->mi_mutex);
 560 
 561         return (rval);
 562 }
 563 
 564 
 565 /*
 566  * attach/resume entry point
 567  */
 568 static int
 569 usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 570 {
 571         int             instance = ddi_get_instance(dip);
 572         usb_mid_t       *usb_mid = NULL;
 573         uint_t          n_ifs, i;
 574         size_t          size;
 575 
 576         switch (cmd) {
 577         case DDI_ATTACH:
 578 
 579                 break;
 580         case DDI_RESUME:
 581                 usb_mid = (usb_mid_t *)ddi_get_soft_state(usb_mid_statep,
 582                     instance);
 583                 (void) usb_mid_restore_device_state(dip, usb_mid);
 584 
 585                 if (usb_mid->mi_ugen_hdl) {
 586                         (void) usb_ugen_attach(usb_mid->mi_ugen_hdl,
 587                             DDI_RESUME);
 588                 }
 589 
 590                 return (DDI_SUCCESS);
 591         default:
 592 
 593                 return (DDI_FAILURE);
 594         }
 595 
 596         /*
 597          * Attach:
 598          *
 599          * Allocate soft state and initialize
 600          */
 601         if (ddi_soft_state_zalloc(usb_mid_statep, instance) != DDI_SUCCESS) {
 602                 goto fail;
 603         }
 604 
 605         usb_mid = ddi_get_soft_state(usb_mid_statep, instance);
 606         if (usb_mid == NULL) {
 607 
 608                 goto fail;
 609         }
 610 
 611         /* allocate handle for logging of messages */
 612         usb_mid->mi_log_handle = usb_alloc_log_hdl(dip, "mid",
 613             &usb_mid_errlevel,
 614             &usb_mid_errmask, &usb_mid_instance_debug,
 615             0);
 616 
 617         usb_mid->mi_usba_device = usba_get_usba_device(dip);
 618         usb_mid->mi_dip      = dip;
 619         usb_mid->mi_instance = instance;
 620         usb_mid->mi_n_ifs = usb_mid->mi_usba_device->usb_n_ifs;
 621 
 622         /* attach client driver to USBA */
 623         if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
 624                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 625                     "usb_client_attach failed");
 626                 goto fail;
 627         }
 628         if (usb_get_dev_data(dip, &usb_mid->mi_dev_data, USB_PARSE_LVL_NONE,
 629             0) != USB_SUCCESS) {
 630                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 631                     "usb_get_dev_data failed");
 632                 goto fail;
 633         }
 634 
 635         mutex_init(&usb_mid->mi_mutex, NULL, MUTEX_DRIVER,
 636             usb_mid->mi_dev_data->dev_iblock_cookie);
 637 
 638         usb_free_dev_data(dip, usb_mid->mi_dev_data);
 639         usb_mid->mi_dev_data = NULL;
 640 
 641         usb_mid->mi_init_state |= USB_MID_LOCK_INIT;
 642 
 643         if (ddi_create_minor_node(dip, "usb_mid", S_IFCHR,
 644             instance << USB_MID_MINOR_INSTANCE_SHIFT,
 645             DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
 646                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 647                     "cannot create devctl minor node");
 648                 goto fail;
 649         }
 650 
 651         usb_mid->mi_init_state |= USB_MID_MINOR_NODE_CREATED;
 652 
 653         /*
 654          * allocate array for keeping track of child dips
 655          */
 656         n_ifs = usb_mid->mi_n_ifs;
 657         usb_mid->mi_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
 658 
 659         usb_mid->mi_children_dips = kmem_zalloc(size, KM_SLEEP);
 660         usb_mid->mi_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
 661             KM_SLEEP);
 662         usb_mid->mi_children_ifs = kmem_zalloc(sizeof (uint_t) * n_ifs,
 663             KM_SLEEP);
 664         for (i = 0; i < n_ifs; i++) {
 665                 usb_mid->mi_children_ifs[i] = 1;
 666         }
 667 
 668         /*
 669          * Event handling: definition and registration
 670          * get event handle for events that we have defined
 671          */
 672         (void) ndi_event_alloc_hdl(dip, 0, &usb_mid->mi_ndi_event_hdl,
 673             NDI_SLEEP);
 674 
 675         /* bind event set to the handle */
 676         if (ndi_event_bind_set(usb_mid->mi_ndi_event_hdl, &usb_mid_ndi_events,
 677             NDI_SLEEP)) {
 678                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 679                     "usb_mid_attach: binding event set failed");
 680 
 681                 goto fail;
 682         }
 683 
 684         usb_mid->mi_dev_state = USB_DEV_ONLINE;
 685 
 686         /*
 687          * now create components to power manage this device
 688          * before attaching children
 689          */
 690         usb_mid_create_pm_components(dip, usb_mid);
 691 
 692         /* event registration for events from our parent */
 693         usba_common_register_events(usb_mid->mi_dip, 1, usb_mid_event_cb);
 694 
 695         usb_mid->mi_init_state |= USB_MID_EVENTS_REGISTERED;
 696 
 697         ddi_report_dev(dip);
 698 
 699         return (DDI_SUCCESS);
 700 
 701 fail:
 702         USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_mid%d cannot attach",
 703             instance);
 704 
 705         if (usb_mid) {
 706                 (void) usb_mid_cleanup(dip, usb_mid);
 707         }
 708 
 709         return (DDI_FAILURE);
 710 }
 711 
 712 
 713 /* detach or suspend this instance */
 714 static int
 715 usb_mid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 716 {
 717         usb_mid_t       *usb_mid = usb_mid_obtain_state(dip);
 718 
 719         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 720             "usb_mid_detach: cmd = 0x%x", cmd);
 721 
 722         switch (cmd) {
 723         case DDI_DETACH:
 724 
 725                 return (usb_mid_cleanup(dip, usb_mid));
 726         case DDI_SUSPEND:
 727                 /* nothing to do */
 728                 mutex_enter(&usb_mid->mi_mutex);
 729                 usb_mid->mi_dev_state = USB_DEV_SUSPENDED;
 730                 mutex_exit(&usb_mid->mi_mutex);
 731 
 732                 if (usb_mid->mi_ugen_hdl) {
 733                         int rval = usb_ugen_detach(usb_mid->mi_ugen_hdl,
 734                             DDI_SUSPEND);
 735                         return (rval == USB_SUCCESS ? DDI_SUCCESS :
 736                             DDI_FAILURE);
 737                 }
 738 
 739                 return (DDI_SUCCESS);
 740         default:
 741 
 742                 return (DDI_FAILURE);
 743         }
 744 
 745         _NOTE(NOT_REACHED)
 746         /* NOTREACHED */
 747 }
 748 
 749 /*
 750  * usb_mid_cleanup:
 751  *      cleanup usb_mid and deallocate. this function is called for
 752  *      handling attach failures and detaching including dynamic
 753  *      reconfiguration
 754  */
 755 /*ARGSUSED*/
 756 static int
 757 usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
 758 {
 759         usb_common_power_t      *midpm;
 760         int             rval;
 761 
 762         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 763             "usb_mid_cleanup:");
 764 
 765         if ((usb_mid->mi_init_state & USB_MID_LOCK_INIT) == 0) {
 766 
 767                 goto done;
 768         }
 769 
 770         /*
 771          * deallocate events, if events are still registered
 772          * (ie. children still attached) then we have to fail the detach
 773          */
 774         if (usb_mid->mi_ndi_event_hdl &&
 775             (ndi_event_free_hdl(usb_mid->mi_ndi_event_hdl) != NDI_SUCCESS)) {
 776 
 777                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 778                     "usb_mid_cleanup: ndi_event_free_hdl failed");
 779 
 780                 return (DDI_FAILURE);
 781         }
 782 
 783         /*
 784          * Disable the event callbacks, after this point, event
 785          * callbacks will never get called. Note we shouldn't hold
 786          * mutex while unregistering events because there may be a
 787          * competing event callback thread. Event callbacks are done
 788          * with ndi mutex held and this can cause a potential deadlock.
 789          * Note that cleanup can't fail after deregistration of events.
 790          */
 791         if (usb_mid->mi_init_state & USB_MID_EVENTS_REGISTERED) {
 792                 usba_common_unregister_events(usb_mid->mi_dip, 1);
 793         }
 794 
 795         midpm = usb_mid->mi_pm;
 796 
 797         mutex_enter(&usb_mid->mi_mutex);
 798 
 799         if ((midpm) && (usb_mid->mi_dev_state != USB_DEV_DISCONNECTED)) {
 800 
 801                 mutex_exit(&usb_mid->mi_mutex);
 802 
 803                 (void) pm_busy_component(dip, 0);
 804                 if (midpm->uc_wakeup_enabled) {
 805 
 806                         /* First bring the device to full power */
 807                         (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
 808 
 809                         rval = usb_handle_remote_wakeup(dip,
 810                             USB_REMOTE_WAKEUP_DISABLE);
 811 
 812                         if (rval != DDI_SUCCESS) {
 813                                 USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
 814                                     usb_mid->mi_log_handle,
 815                                     "usb_cleanup: disable remote "
 816                                     "wakeup failed, rval=%d", rval);
 817                         }
 818                 }
 819 
 820                 (void) pm_lower_power(usb_mid->mi_dip, 0, USB_DEV_OS_PWR_OFF);
 821                 (void) pm_idle_component(dip, 0);
 822         } else {
 823                 mutex_exit(&usb_mid->mi_mutex);
 824         }
 825 
 826         if (midpm) {
 827                 kmem_free(midpm, sizeof (usb_common_power_t));
 828         }
 829 
 830         /* free children list */
 831         if (usb_mid->mi_children_dips) {
 832                 kmem_free(usb_mid->mi_children_dips,
 833                     usb_mid->mi_cd_list_length);
 834         }
 835 
 836         if (usb_mid->mi_child_events) {
 837                 kmem_free(usb_mid->mi_child_events, sizeof (uint8_t) *
 838                     usb_mid->mi_n_ifs);
 839         }
 840 
 841         if (usb_mid->mi_children_ifs) {
 842                 kmem_free(usb_mid->mi_children_ifs, sizeof (uint_t) *
 843                     usb_mid->mi_n_ifs);
 844         }
 845 
 846         if (usb_mid->mi_init_state & USB_MID_MINOR_NODE_CREATED) {
 847                 ddi_remove_minor_node(dip, NULL);
 848         }
 849 
 850         mutex_destroy(&usb_mid->mi_mutex);
 851 
 852 done:
 853         usb_client_detach(dip, usb_mid->mi_dev_data);
 854 
 855         if (usb_mid->mi_ugen_hdl) {
 856                 (void) usb_ugen_detach(usb_mid->mi_ugen_hdl, DDI_DETACH);
 857                 usb_ugen_release_hdl(usb_mid->mi_ugen_hdl);
 858         }
 859 
 860         usb_free_log_hdl(usb_mid->mi_log_handle);
 861         ddi_soft_state_free(usb_mid_statep, ddi_get_instance(dip));
 862 
 863         ddi_prop_remove_all(dip);
 864 
 865         return (DDI_SUCCESS);
 866 }
 867 
 868 
 869 static void
 870 usb_mid_ugen_attach(usb_mid_t *usb_mid, boolean_t remove_children)
 871 {
 872         _NOTE(NO_COMPETING_THREADS_NOW);
 873 
 874         if (usb_mid->mi_ugen_hdl == NULL) {
 875                 usb_ugen_info_t usb_ugen_info;
 876                 int             rval;
 877                 usb_ugen_hdl_t  hdl;
 878 
 879                 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 880                     "usb_mid_ugen_attach: get handle");
 881 
 882                 bzero(&usb_ugen_info, sizeof (usb_ugen_info));
 883 
 884                 usb_ugen_info.usb_ugen_flags = (remove_children ?
 885                     USB_UGEN_REMOVE_CHILDREN : 0);
 886                 usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
 887                     (dev_t)USB_MID_MINOR_UGEN_BITS_MASK;
 888                 usb_ugen_info.usb_ugen_minor_node_instance_mask =
 889                     (dev_t)~USB_MID_MINOR_UGEN_BITS_MASK;
 890 
 891                 mutex_exit(&usb_mid->mi_mutex);
 892                 hdl = usb_ugen_get_hdl(usb_mid->mi_dip,
 893                     &usb_ugen_info);
 894 
 895                 if ((rval = usb_ugen_attach(hdl, DDI_ATTACH)) != USB_SUCCESS) {
 896                         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 897                             "failed to create ugen support (%d)", rval);
 898                         usb_ugen_release_hdl(hdl);
 899 
 900                         mutex_enter(&usb_mid->mi_mutex);
 901                 } else {
 902                         mutex_enter(&usb_mid->mi_mutex);
 903                         usb_mid->mi_ugen_hdl = hdl;
 904                 }
 905         }
 906 
 907 #ifndef lint
 908         _NOTE(COMPETING_THREADS_NOW);
 909 #endif
 910 }
 911 
 912 
 913 /*
 914  * usb_mid_create_children:
 915  */
 916 static void
 917 usb_mid_create_children(usb_mid_t *usb_mid)
 918 {
 919         usba_device_t           *usba_device;
 920         uint_t                  n_ifs, if_count;
 921         uint_t                  i, j;
 922         dev_info_t              *cdip, *ia_dip;
 923         uint_t                  ugen_bound = 0;
 924         uint_t                  bound_children = 0;
 925 
 926         usba_device = usba_get_usba_device(usb_mid->mi_dip);
 927 
 928         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 929             "usb_mid_attach_child_drivers: port = %d, address = %d",
 930             usba_device->usb_port, usba_device->usb_addr);
 931 
 932         if (usb_mid->mi_removed_children) {
 933 
 934                         return;
 935         }
 936 
 937         n_ifs = usb_mid->mi_n_ifs;
 938         if_count = 1;
 939 
 940         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
 941             "usb_mid_create_children: #interfaces = %d", n_ifs);
 942 
 943         /*
 944          * create all children if not already present
 945          */
 946         for (i = 0; i < n_ifs; i += if_count) {
 947 
 948                 /* ignore since this if is included by an ia */
 949                 if (usb_mid->mi_children_ifs[i] == 0) {
 950 
 951                         continue;
 952                 }
 953 
 954                 if (usb_mid->mi_children_dips[i] != NULL) {
 955                         if (i_ddi_node_state(
 956                             usb_mid->mi_children_dips[i]) >=
 957                             DS_BOUND) {
 958                                         bound_children++;
 959                         }
 960 
 961                         continue;
 962                 }
 963 
 964                 mutex_exit(&usb_mid->mi_mutex);
 965                 ia_dip = usba_ready_interface_association_node(usb_mid->mi_dip,
 966                     i, &if_count);
 967 
 968                 if (ia_dip != NULL) {
 969                         if (usba_bind_driver(ia_dip) == USB_SUCCESS) {
 970                                 bound_children++;
 971                                 if (strcmp(ddi_driver_name(ia_dip),
 972                                     "ugen") == 0) {
 973                                         ugen_bound++;
 974                                 }
 975                         }
 976 
 977                         /*
 978                          * IA node owns if_count interfaces.
 979                          * The rest interfaces own none.
 980                          */
 981                         mutex_enter(&usb_mid->mi_mutex);
 982                         usb_mid->mi_children_dips[i] = ia_dip;
 983                         usb_mid->mi_children_ifs[i] = if_count;
 984                         for (j = i + 1; j < i + if_count; j++) {
 985                                 usb_mid->mi_children_ifs[j] = 0;
 986                         }
 987 
 988                         continue;
 989                 }
 990 
 991                 cdip = usba_ready_interface_node(usb_mid->mi_dip, i);
 992 
 993                 if (cdip != NULL) {
 994                         if (usba_bind_driver(cdip) ==
 995                             USB_SUCCESS) {
 996                                 bound_children++;
 997                                 if (strcmp(ddi_driver_name(cdip),
 998                                     "ugen") == 0) {
 999                                         ugen_bound++;
1000                                 }
1001                         }
1002 
1003                         /*
1004                          * interface node owns 1 interface always.
1005                          */
1006                         mutex_enter(&usb_mid->mi_mutex);
1007                         usb_mid->mi_children_dips[i] = cdip;
1008                         usb_mid->mi_children_ifs[i] = 1;
1009                         mutex_exit(&usb_mid->mi_mutex);
1010 
1011                 }
1012 
1013                 mutex_enter(&usb_mid->mi_mutex);
1014         }
1015 
1016         usb_mid->mi_removed_children = (bound_children ? B_FALSE : B_TRUE);
1017 
1018         /*
1019          * if there are no ugen interface children, create ugen support at
1020          * device level, use a separate thread because we may be at interrupt
1021          * level
1022          */
1023         if ((ugen_bound == 0) && (usb_mid->mi_ugen_hdl == NULL)) {
1024                 /*
1025                  * we only need to remove the children if there are
1026                  * multiple configurations which would fail if there
1027                  * are child interfaces
1028                  */
1029                 if ((usb_mid->mi_removed_children == B_FALSE) &&
1030                     (usba_device->usb_n_cfgs > 1)) {
1031                         USB_DPRINTF_L1(DPRINT_MASK_ATTA,
1032                             usb_mid->mi_log_handle,
1033                             "can't support ugen for multiple "
1034                             "configurations devices that have attached "
1035                             "child interface drivers");
1036                 } else {
1037                         usb_mid_ugen_attach(usb_mid,
1038                             usb_mid->mi_removed_children);
1039                 }
1040         }
1041 }
1042 
1043 
1044 /*
1045  * event support
1046  */
1047 static int
1048 usb_mid_busop_get_eventcookie(dev_info_t *dip,
1049         dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
1050 {
1051         usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1052 
1053         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1054             "usb_mid_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
1055             "event=%s", (void *)dip, (void *)rdip, eventname);
1056         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1057             "(dip=%s%d rdip=%s%d)",
1058             ddi_driver_name(dip), ddi_get_instance(dip),
1059             ddi_driver_name(rdip), ddi_get_instance(rdip));
1060 
1061         /* return event cookie, iblock cookie, and level */
1062         return (ndi_event_retrieve_cookie(usb_mid->mi_ndi_event_hdl,
1063             rdip, eventname, cookie, NDI_EVENT_NOPASS));
1064 }
1065 
1066 
1067 static int
1068 usb_mid_busop_add_eventcall(dev_info_t *dip,
1069         dev_info_t *rdip,
1070         ddi_eventcookie_t cookie,
1071         void (*callback)(dev_info_t *dip,
1072             ddi_eventcookie_t cookie, void *arg,
1073             void *bus_impldata),
1074         void *arg, ddi_callback_id_t *cb_id)
1075 {
1076         usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1077         int     ifno = usba_get_ifno(rdip);
1078 
1079         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1080             "usb_mid_busop_add_eventcall: dip=0x%p, rdip=0x%p "
1081             "cookie=0x%p, cb=0x%p, arg=0x%p",
1082             (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
1083         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1084             "(dip=%s%d rdip=%s%d event=%s)",
1085             ddi_driver_name(dip), ddi_get_instance(dip),
1086             ddi_driver_name(rdip), ddi_get_instance(rdip),
1087             ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1088 
1089         /* Set flag on children registering events */
1090         switch (ndi_event_cookie_to_tag(usb_mid->mi_ndi_event_hdl, cookie)) {
1091         case USBA_EVENT_TAG_HOT_REMOVAL:
1092                 mutex_enter(&usb_mid->mi_mutex);
1093                 usb_mid->mi_child_events[ifno] |=
1094                     USB_MID_CHILD_EVENT_DISCONNECT;
1095                 mutex_exit(&usb_mid->mi_mutex);
1096 
1097                 break;
1098         case USBA_EVENT_TAG_PRE_SUSPEND:
1099                 mutex_enter(&usb_mid->mi_mutex);
1100                 usb_mid->mi_child_events[ifno] |=
1101                     USB_MID_CHILD_EVENT_PRESUSPEND;
1102                 mutex_exit(&usb_mid->mi_mutex);
1103 
1104                 break;
1105         default:
1106 
1107                 break;
1108         }
1109         /* add callback (perform registration) */
1110         return (ndi_event_add_callback(usb_mid->mi_ndi_event_hdl,
1111             rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
1112 }
1113 
1114 
1115 static int
1116 usb_mid_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
1117 {
1118         usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1119         ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
1120 
1121         ASSERT(cb);
1122 
1123         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1124             "usb_mid_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
1125             "cookie=0x%p", (void *)dip, (void *)cb->ndi_evtcb_dip,
1126             (void *)cb->ndi_evtcb_cookie);
1127         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1128             "(dip=%s%d rdip=%s%d event=%s)",
1129             ddi_driver_name(dip), ddi_get_instance(dip),
1130             ddi_driver_name(cb->ndi_evtcb_dip),
1131             ddi_get_instance(cb->ndi_evtcb_dip),
1132             ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl,
1133             cb->ndi_evtcb_cookie));
1134 
1135         /* remove event registration from our event set */
1136         return (ndi_event_remove_callback(usb_mid->mi_ndi_event_hdl, cb_id));
1137 }
1138 
1139 
1140 static int
1141 usb_mid_busop_post_event(dev_info_t *dip,
1142         dev_info_t *rdip,
1143         ddi_eventcookie_t cookie,
1144         void *bus_impldata)
1145 {
1146         usb_mid_t  *usb_mid = usb_mid_obtain_state(dip);
1147 
1148         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1149             "usb_mid_busop_post_event: dip=0x%p, rdip=0x%p "
1150             "cookie=0x%p, impl=0x%p",
1151             (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
1152         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1153             "(dip=%s%d rdip=%s%d event=%s)",
1154             ddi_driver_name(dip), ddi_get_instance(dip),
1155             ddi_driver_name(rdip), ddi_get_instance(rdip),
1156             ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1157 
1158         /* post event to all children registered for this event */
1159         return (ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, rdip,
1160             cookie, bus_impldata));
1161 }
1162 
1163 
1164 /*
1165  * usb_mid_restore_device_state
1166  *      set the original configuration of the device
1167  */
1168 static int
1169 usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid)
1170 {
1171         usb_common_power_t              *midpm;
1172 
1173         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1174             "usb_mid_restore_device_state: usb_mid = %p", (void *)usb_mid);
1175 
1176         mutex_enter(&usb_mid->mi_mutex);
1177         midpm = usb_mid->mi_pm;
1178         mutex_exit(&usb_mid->mi_mutex);
1179 
1180         /* First bring the device to full power */
1181         (void) pm_busy_component(dip, 0);
1182         (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1183 
1184         if (usb_check_same_device(dip, usb_mid->mi_log_handle, USB_LOG_L0,
1185             DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
1186 
1187                 /* change the device state from suspended to disconnected */
1188                 mutex_enter(&usb_mid->mi_mutex);
1189                 usb_mid->mi_dev_state = USB_DEV_DISCONNECTED;
1190                 mutex_exit(&usb_mid->mi_mutex);
1191                 (void) pm_idle_component(dip, 0);
1192 
1193                 return (USB_FAILURE);
1194         }
1195 
1196         /*
1197          * if the device had remote wakeup earlier,
1198          * enable it again
1199          */
1200         if (midpm->uc_wakeup_enabled) {
1201                 (void) usb_handle_remote_wakeup(usb_mid->mi_dip,
1202                     USB_REMOTE_WAKEUP_ENABLE);
1203         }
1204 
1205         mutex_enter(&usb_mid->mi_mutex);
1206         usb_mid->mi_dev_state = USB_DEV_ONLINE;
1207         mutex_exit(&usb_mid->mi_mutex);
1208 
1209         (void) pm_idle_component(dip, 0);
1210 
1211         return (USB_SUCCESS);
1212 }
1213 
1214 
1215 /*
1216  * usb_mid_event_cb()
1217  *      handle disconnect and connect events
1218  */
1219 static void
1220 usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
1221         void *arg, void *bus_impldata)
1222 {
1223         int             i, tag;
1224         usb_mid_t       *usb_mid = usb_mid_obtain_state(dip);
1225         dev_info_t      *child_dip;
1226         ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
1227 
1228         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1229             "usb_mid_event_cb: dip=0x%p, cookie=0x%p, "
1230             "arg=0x%p, impl=0x%p",
1231             (void *)dip, (void *)cookie, arg, bus_impldata);
1232         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1233             "(dip=%s%d event=%s)",
1234             ddi_driver_name(dip), ddi_get_instance(dip),
1235             ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1236 
1237         tag = NDI_EVENT_TAG(cookie);
1238         rm_cookie = ndi_event_tag_to_cookie(
1239             usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
1240         suspend_cookie = ndi_event_tag_to_cookie(
1241             usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
1242         ins_cookie = ndi_event_tag_to_cookie(
1243             usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
1244         resume_cookie = ndi_event_tag_to_cookie(
1245             usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
1246 
1247         mutex_enter(&usb_mid->mi_mutex);
1248         switch (tag) {
1249         case USBA_EVENT_TAG_HOT_REMOVAL:
1250                 if (usb_mid->mi_dev_state == USB_DEV_DISCONNECTED) {
1251                         USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
1252                             usb_mid->mi_log_handle,
1253                             "usb_mid_event_cb: Device already disconnected");
1254                 } else {
1255                         /* we are disconnected so set our state now */
1256                         usb_mid->mi_dev_state = USB_DEV_DISCONNECTED;
1257                         for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1258                                 usb_mid->mi_child_events[i] &= ~
1259                                     USB_MID_CHILD_EVENT_DISCONNECT;
1260                         }
1261                         mutex_exit(&usb_mid->mi_mutex);
1262 
1263                         /* pass disconnect event to all the children */
1264                         (void) ndi_event_run_callbacks(
1265                             usb_mid->mi_ndi_event_hdl, NULL,
1266                             rm_cookie, bus_impldata);
1267 
1268                         if (usb_mid->mi_ugen_hdl) {
1269                                 (void) usb_ugen_disconnect_ev_cb(
1270                                     usb_mid->mi_ugen_hdl);
1271                         }
1272                         mutex_enter(&usb_mid->mi_mutex);
1273                 }
1274                 break;
1275         case USBA_EVENT_TAG_PRE_SUSPEND:
1276                 /* set our state *after* suspending children */
1277                 mutex_exit(&usb_mid->mi_mutex);
1278 
1279                 /* pass pre_suspend event to all the children */
1280                 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl,
1281                     NULL, suspend_cookie, bus_impldata);
1282 
1283                 mutex_enter(&usb_mid->mi_mutex);
1284                 for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1285                         usb_mid->mi_child_events[i] &= ~
1286                             USB_MID_CHILD_EVENT_PRESUSPEND;
1287                 }
1288                 break;
1289         case USBA_EVENT_TAG_HOT_INSERTION:
1290                 mutex_exit(&usb_mid->mi_mutex);
1291                 if (usb_mid_restore_device_state(dip, usb_mid) == USB_SUCCESS) {
1292 
1293                         /*
1294                          * Check to see if this child has missed the disconnect
1295                          * event before it registered for event cb
1296                          */
1297                         mutex_enter(&usb_mid->mi_mutex);
1298                         for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1299                                 if ((usb_mid->mi_child_events[i] &
1300                                     USB_MID_CHILD_EVENT_DISCONNECT) &&
1301                                     usb_mid->mi_children_ifs[i]) {
1302                                         usb_mid->mi_child_events[i] &=
1303                                             ~USB_MID_CHILD_EVENT_DISCONNECT;
1304                                         child_dip =
1305                                             usb_mid->mi_children_dips[i];
1306                                         mutex_exit(&usb_mid->mi_mutex);
1307 
1308                                         /* post the missed disconnect */
1309                                         (void) ndi_event_do_callback(
1310                                             usb_mid->mi_ndi_event_hdl,
1311                                             child_dip,
1312                                             rm_cookie,
1313                                             bus_impldata);
1314                                         mutex_enter(&usb_mid->mi_mutex);
1315                                 }
1316                         }
1317                         mutex_exit(&usb_mid->mi_mutex);
1318 
1319                         /* pass reconnect event to all the children */
1320                         (void) ndi_event_run_callbacks(
1321                             usb_mid->mi_ndi_event_hdl, NULL,
1322                             ins_cookie, bus_impldata);
1323 
1324                         if (usb_mid->mi_ugen_hdl) {
1325                                 (void) usb_ugen_reconnect_ev_cb(
1326                                     usb_mid->mi_ugen_hdl);
1327                         }
1328                 }
1329                 mutex_enter(&usb_mid->mi_mutex);
1330                 break;
1331         case USBA_EVENT_TAG_POST_RESUME:
1332                 /*
1333                  * Check to see if this child has missed the pre-suspend
1334                  * event before it registered for event cb
1335                  */
1336                 for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1337                         if ((usb_mid->mi_child_events[i] &
1338                             USB_MID_CHILD_EVENT_PRESUSPEND) &&
1339                             usb_mid->mi_children_ifs[i]) {
1340                                 usb_mid->mi_child_events[i] &=
1341                                     ~USB_MID_CHILD_EVENT_PRESUSPEND;
1342                                 child_dip = usb_mid->mi_children_dips[i];
1343                                 mutex_exit(&usb_mid->mi_mutex);
1344 
1345                                 /* post the missed pre-suspend event */
1346                                 (void) ndi_event_do_callback(
1347                                     usb_mid->mi_ndi_event_hdl,
1348                                     child_dip, suspend_cookie,
1349                                     bus_impldata);
1350                                 mutex_enter(&usb_mid->mi_mutex);
1351                         }
1352                 }
1353                 mutex_exit(&usb_mid->mi_mutex);
1354 
1355                 /* pass post_resume event to all the children */
1356                 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl,
1357                     NULL, resume_cookie, bus_impldata);
1358 
1359                 mutex_enter(&usb_mid->mi_mutex);
1360                 break;
1361         }
1362         mutex_exit(&usb_mid->mi_mutex);
1363 
1364 }
1365 
1366 
1367 /*
1368  * create the pm components required for power management
1369  */
1370 static void
1371 usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid)
1372 {
1373         usb_common_power_t      *midpm;
1374         uint_t          pwr_states;
1375 
1376         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1377             "usb_mid_create_pm_components: Begin");
1378 
1379         /* Allocate the PM state structure */
1380         midpm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
1381 
1382         mutex_enter(&usb_mid->mi_mutex);
1383         usb_mid->mi_pm = midpm;
1384         midpm->uc_usb_statep = usb_mid;
1385         midpm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
1386         midpm->uc_current_power = USB_DEV_OS_FULL_PWR;
1387         mutex_exit(&usb_mid->mi_mutex);
1388 
1389         /*
1390          * By not enabling parental notification, PM enforces
1391          * "strict parental dependency" meaning, usb_mid won't
1392          * power off until any of its children are in full power.
1393          */
1394 
1395         /*
1396          * there are 3 scenarios:
1397          * 1. a well behaved device should have remote wakeup
1398          * at interface and device level. If the interface
1399          * wakes up, usb_mid will wake up
1400          * 2. if the device doesn't have remote wake up and
1401          * the interface has, PM will still work, ie.
1402          * the interfaces wakes up and usb_mid wakes up
1403          * 3. if neither the interface nor device has remote
1404          * wakeup, the interface will wake up when it is opened
1405          * and goes to sleep after being closed for a while
1406          * In this case usb_mid should also go to sleep shortly
1407          * thereafter
1408          * In all scenarios it doesn't really matter whether
1409          * remote wakeup at the device level is enabled or not
1410          * but we do it anyways
1411          */
1412         if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
1413             USB_SUCCESS) {
1414                 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1415                     "usb_mid_create_pm_components: "
1416                     "Remote Wakeup Enabled");
1417                 midpm->uc_wakeup_enabled = 1;
1418         }
1419 
1420         if (usb_create_pm_components(dip, &pwr_states) ==
1421             USB_SUCCESS) {
1422                 midpm->uc_pwr_states = (uint8_t)pwr_states;
1423                 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1424         }
1425 
1426         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1427             "usb_mid_create_pm_components: End");
1428 }
1429 
1430 
1431 /*
1432  * usb_mid_obtain_state:
1433  */
1434 usb_mid_t *
1435 usb_mid_obtain_state(dev_info_t *dip)
1436 {
1437         int instance = ddi_get_instance(dip);
1438         usb_mid_t *statep = ddi_get_soft_state(usb_mid_statep, instance);
1439 
1440         ASSERT(statep != NULL);
1441 
1442         return (statep);
1443 }
1444 
1445 
1446 /*
1447  * ugen support
1448  */
1449 /* ARGSUSED3 */
1450 static int
1451 usb_mid_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1452 {
1453         struct usb_mid *usb_mid;
1454         int     rval;
1455 
1456         if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1457             USB_MID_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) {
1458 
1459                 return (ENXIO);
1460         }
1461 
1462         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, usb_mid->mi_log_handle,
1463             "usb_mid_open: usb_mid = 0x%p *devp = 0x%lx",
1464             (void *)usb_mid, *devp);
1465 
1466         /* First bring the device to full power */
1467         (void) pm_busy_component(usb_mid->mi_dip, 0);
1468         (void) pm_raise_power(usb_mid->mi_dip, 0, USB_DEV_OS_FULL_PWR);
1469 
1470 
1471         rval = usb_ugen_open(usb_mid->mi_ugen_hdl, devp, flags, otyp,
1472             credp);
1473         if (rval) {
1474                 (void) pm_idle_component(usb_mid->mi_dip, 0);
1475         } else {
1476                 /*
1477                  * since all ugen opens are exclusive we can count the
1478                  * opens
1479                  */
1480                 mutex_enter(&usb_mid->mi_mutex);
1481                 usb_mid->mi_ugen_open_count++;
1482                 mutex_exit(&usb_mid->mi_mutex);
1483         }
1484 
1485         return (rval);
1486 }
1487 
1488 
1489 /* ARGSUSED */
1490 static int
1491 usb_mid_close(dev_t dev, int flag, int otyp, cred_t *credp)
1492 {
1493         struct usb_mid *usb_mid;
1494         int rval;
1495 
1496         if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1497             USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1498 
1499                 return (ENXIO);
1500         }
1501 
1502         rval = usb_ugen_close(usb_mid->mi_ugen_hdl, dev, flag, otyp,
1503             credp);
1504         if (rval == 0) {
1505                 (void) pm_idle_component(usb_mid->mi_dip, 0);
1506                 mutex_enter(&usb_mid->mi_mutex);
1507                 usb_mid->mi_ugen_open_count--;
1508                 mutex_exit(&usb_mid->mi_mutex);
1509         }
1510 
1511         return (rval);
1512 }
1513 
1514 
1515 static int
1516 usb_mid_read(dev_t dev, struct uio *uio, cred_t *credp)
1517 {
1518         struct usb_mid *usb_mid;
1519 
1520         if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1521             USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1522 
1523                 return (ENXIO);
1524         }
1525 
1526         return (usb_ugen_read(usb_mid->mi_ugen_hdl, dev, uio, credp));
1527 }
1528 
1529 
1530 static int
1531 usb_mid_write(dev_t dev, struct uio *uio, cred_t *credp)
1532 {
1533         struct usb_mid *usb_mid;
1534 
1535         if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1536             USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1537 
1538                 return (ENXIO);
1539         }
1540 
1541         return (usb_ugen_write(usb_mid->mi_ugen_hdl, dev, uio, credp));
1542 }
1543 
1544 
1545 static int
1546 usb_mid_poll(dev_t dev, short events, int anyyet,  short *reventsp,
1547     struct pollhead **phpp)
1548 {
1549         struct usb_mid *usb_mid;
1550 
1551         if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1552             USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1553 
1554                 return (ENXIO);
1555         }
1556 
1557         return (usb_ugen_poll(usb_mid->mi_ugen_hdl, dev, events,
1558             anyyet, reventsp, phpp));
1559 }