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  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  27  */
  28 
  29 
  30 /*
  31  * usb interface association driver
  32  *
  33  *      this driver attempts to the interface association node and
  34  *      creates/manages child nodes for the included interfaces.
  35  */
  36 
  37 #if defined(lint) && !defined(DEBUG)
  38 #define DEBUG   1
  39 #endif
  40 #include <sys/usb/usba/usbai_version.h>
  41 #include <sys/usb/usba.h>
  42 #include <sys/usb/usba/usba_types.h>
  43 #include <sys/usb/usba/usba_impl.h>
  44 #include <sys/usb/usb_ia/usb_iavar.h>
  45 
  46 /* Debugging support */
  47 uint_t usb_ia_errlevel = USB_LOG_L4;
  48 uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL;
  49 uint_t usb_ia_instance_debug = (uint_t)-1;
  50 uint_t usb_ia_bus_config_debug = 0;
  51 
  52 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel))
  53 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask))
  54 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug))
  55 
  56 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
  57 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
  58 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
  59 
  60 static struct cb_ops usb_ia_cb_ops = {
  61         nodev,          /* open */
  62         nodev,          /* close */
  63         nodev,          /* strategy */
  64         nodev,          /* print */
  65         nodev,          /* dump */
  66         nodev,          /* read */
  67         nodev,          /* write */
  68         nodev,          /* ioctl */
  69         nodev,          /* devmap */
  70         nodev,          /* mmap */
  71         nodev,          /* segmap */
  72         nochpoll,       /* poll */
  73         ddi_prop_op,    /* prop_op */
  74         NULL,           /* aread */
  75         D_MP
  76 };
  77 
  78 static int usb_ia_busop_get_eventcookie(dev_info_t *dip,
  79                         dev_info_t *rdip,
  80                         char *eventname,
  81                         ddi_eventcookie_t *cookie);
  82 static int usb_ia_busop_add_eventcall(dev_info_t *dip,
  83                         dev_info_t *rdip,
  84                         ddi_eventcookie_t cookie,
  85                         void (*callback)(dev_info_t *dip,
  86                                 ddi_eventcookie_t cookie, void *arg,
  87                                 void *bus_impldata),
  88                         void *arg, ddi_callback_id_t *cb_id);
  89 static int usb_ia_busop_remove_eventcall(dev_info_t *dip,
  90                         ddi_callback_id_t cb_id);
  91 static int usb_ia_busop_post_event(dev_info_t *dip,
  92                         dev_info_t *rdip,
  93                         ddi_eventcookie_t cookie,
  94                         void *bus_impldata);
  95 static int usb_ia_bus_config(dev_info_t *dip,
  96                         uint_t flag,
  97                         ddi_bus_config_op_t op,
  98                         void *arg,
  99                         dev_info_t **child);
 100 static int usb_ia_bus_unconfig(dev_info_t *dip,
 101                         uint_t flag,
 102                         ddi_bus_config_op_t op,
 103                         void *arg);
 104 
 105 /*
 106  * autoconfiguration data and routines.
 107  */
 108 static int      usb_ia_info(dev_info_t *, ddi_info_cmd_t,
 109                                 void *, void **);
 110 static int      usb_ia_attach(dev_info_t *, ddi_attach_cmd_t);
 111 static int      usb_ia_detach(dev_info_t *, ddi_detach_cmd_t);
 112 
 113 /* other routines */
 114 static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *);
 115 static int usb_ia_bus_ctl(dev_info_t *, dev_info_t      *,
 116                                 ddi_ctl_enum_t, void *, void *);
 117 static int usb_ia_power(dev_info_t *, int, int);
 118 static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *);
 119 static usb_ia_t  *usb_ia_obtain_state(dev_info_t *);
 120 static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
 121 
 122 /* prototypes */
 123 static void usb_ia_create_children(usb_ia_t *);
 124 static int usb_ia_cleanup(usb_ia_t *);
 125 
 126 /*
 127  * Busops vector
 128  */
 129 static struct bus_ops usb_ia_busops = {
 130         BUSO_REV,
 131         nullbusmap,                     /* bus_map */
 132         NULL,                           /* bus_get_intrspec */
 133         NULL,                           /* bus_add_intrspec */
 134         NULL,                           /* bus_remove_intrspec */
 135         NULL,                           /* XXXX bus_map_fault */
 136         NULL,                           /* bus_dma_map */
 137         ddi_dma_allochdl,
 138         ddi_dma_freehdl,
 139         ddi_dma_bindhdl,
 140         ddi_dma_unbindhdl,
 141         ddi_dma_flush,
 142         ddi_dma_win,
 143         ddi_dma_mctl,                   /* bus_dma_ctl */
 144         usb_ia_bus_ctl,         /* bus_ctl */
 145         ddi_bus_prop_op,                /* bus_prop_op */
 146         usb_ia_busop_get_eventcookie,
 147         usb_ia_busop_add_eventcall,
 148         usb_ia_busop_remove_eventcall,
 149         usb_ia_busop_post_event,        /* bus_post_event */
 150         NULL,                           /* bus_intr_ctl */
 151         usb_ia_bus_config,              /* bus_config */
 152         usb_ia_bus_unconfig,            /* bus_unconfig */
 153         NULL,                           /* bus_fm_init */
 154         NULL,                           /* bus_fm_fini */
 155         NULL,                           /* bus_fm_access_enter */
 156         NULL,                           /* bus_fm_access_exit */
 157         NULL                            /* bus_power */
 158 };
 159 
 160 
 161 static struct dev_ops usb_ia_ops = {
 162         DEVO_REV,               /* devo_rev, */
 163         0,                      /* refcnt  */
 164         usb_ia_info,            /* info */
 165         nulldev,                /* identify */
 166         nulldev,                /* probe */
 167         usb_ia_attach,          /* attach */
 168         usb_ia_detach,          /* detach */
 169         nodev,                  /* reset */
 170         &usb_ia_cb_ops,     /* driver operations */
 171         &usb_ia_busops,     /* bus operations */
 172         usb_ia_power,           /* power */
 173         ddi_quiesce_not_needed, /* devo_quiesce */
 174 };
 175 
 176 static struct modldrv modldrv = {
 177         &mod_driverops, /* Type of module. This one is a driver */
 178         "USB Interface Association Driver", /* Name of the module. */
 179         &usb_ia_ops,        /* driver ops */
 180 };
 181 
 182 static struct modlinkage modlinkage = {
 183         MODREV_1, (void *)&modldrv, NULL
 184 };
 185 
 186 #define USB_IA_INITIAL_SOFT_SPACE 4
 187 static  void    *usb_ia_statep;
 188 
 189 /*
 190  * event definition
 191  */
 192 static ndi_event_definition_t usb_ia_ndi_event_defs[] = {
 193         {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
 194                                                 NDI_EVENT_POST_TO_ALL},
 195         {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
 196                                                 NDI_EVENT_POST_TO_ALL},
 197         {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
 198                                                 NDI_EVENT_POST_TO_ALL},
 199         {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
 200                                                 NDI_EVENT_POST_TO_ALL}
 201 };
 202 
 203 #define USB_IA_N_NDI_EVENTS \
 204         (sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t))
 205 
 206 static  ndi_event_set_t usb_ia_ndi_events = {
 207         NDI_EVENTS_REV1, USB_IA_N_NDI_EVENTS, usb_ia_ndi_event_defs};
 208 
 209 
 210 /*
 211  * standard driver entry points
 212  */
 213 int
 214 _init(void)
 215 {
 216         int rval;
 217 
 218         rval = ddi_soft_state_init(&usb_ia_statep, sizeof (struct usb_ia),
 219             USB_IA_INITIAL_SOFT_SPACE);
 220         if (rval != 0) {
 221                 return (rval);
 222         }
 223 
 224         if ((rval = mod_install(&modlinkage)) != 0) {
 225                 ddi_soft_state_fini(&usb_ia_statep);
 226                 return (rval);
 227         }
 228 
 229         return (rval);
 230 }
 231 
 232 
 233 int
 234 _fini(void)
 235 {
 236         int     rval;
 237 
 238         rval = mod_remove(&modlinkage);
 239 
 240         if (rval) {
 241                 return (rval);
 242         }
 243 
 244         ddi_soft_state_fini(&usb_ia_statep);
 245 
 246         return (rval);
 247 }
 248 
 249 
 250 int
 251 _info(struct modinfo *modinfop)
 252 {
 253         return (mod_info(&modlinkage, modinfop));
 254 }
 255 
 256 
 257 /*ARGSUSED*/
 258 static int
 259 usb_ia_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 260 {
 261         usb_ia_t        *usb_ia;
 262         int             instance = getminor((dev_t)arg);
 263         int             error = DDI_FAILURE;
 264 
 265         switch (infocmd) {
 266         case DDI_INFO_DEVT2DEVINFO:
 267                 if ((usb_ia = ddi_get_soft_state(usb_ia_statep,
 268                     instance)) != NULL) {
 269                         *result = (void *)usb_ia->ia_dip;
 270                         if (*result != NULL) {
 271                                 error = DDI_SUCCESS;
 272                         }
 273                 } else {
 274                         *result = NULL;
 275                 }
 276                 break;
 277 
 278         case DDI_INFO_DEVT2INSTANCE:
 279                 *result = (void *)(intptr_t)instance;
 280                 error = DDI_SUCCESS;
 281                 break;
 282         default:
 283                 break;
 284         }
 285 
 286         return (error);
 287 }
 288 
 289 
 290 /*
 291  * child  post attach/detach notification
 292  */
 293 static void
 294 usb_ia_post_attach(usb_ia_t *usb_ia, uint8_t ifno, struct attachspec *as)
 295 {
 296         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
 297             "usb_ia_post_attach: ifno = %d result = %d", ifno, as->result);
 298 
 299 }
 300 
 301 
 302 static void
 303 usb_ia_post_detach(usb_ia_t *usb_ia, uint8_t ifno, struct detachspec *ds)
 304 {
 305         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
 306             "usb_ia_post_detach: ifno = %d result = %d", ifno, ds->result);
 307 
 308 }
 309 
 310 
 311 /*
 312  * bus ctl support. we handle notifications here and the
 313  * rest goes up to root hub/hcd
 314  */
 315 /*ARGSUSED*/
 316 static int
 317 usb_ia_bus_ctl(dev_info_t *dip,
 318         dev_info_t      *rdip,
 319         ddi_ctl_enum_t  op,
 320         void            *arg,
 321         void            *result)
 322 {
 323         usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
 324         dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
 325         usb_ia_t  *usb_ia;
 326         struct attachspec *as;
 327         struct detachspec *ds;
 328 
 329         usb_ia = usb_ia_obtain_state(dip);
 330 
 331         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
 332             "usb_ia_bus_ctl:\n\t"
 333             "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
 334             (void *)dip, (void *)rdip, op, arg);
 335 
 336         switch (op) {
 337         case DDI_CTLOPS_ATTACH:
 338                 as = (struct attachspec *)arg;
 339 
 340                 switch (as->when) {
 341                 case DDI_PRE :
 342                         /* nothing to do basically */
 343                         USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
 344                             "DDI_PRE DDI_CTLOPS_ATTACH");
 345                         break;
 346                 case DDI_POST :
 347                         usb_ia_post_attach(usb_ia, usba_get_ifno(rdip),
 348                             (struct attachspec *)arg);
 349                         break;
 350                 }
 351 
 352                 break;
 353         case DDI_CTLOPS_DETACH:
 354                 ds = (struct detachspec *)arg;
 355 
 356                 switch (ds->when) {
 357                 case DDI_PRE :
 358                         /* nothing to do basically */
 359                         USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
 360                             "DDI_PRE DDI_CTLOPS_DETACH");
 361                         break;
 362                 case DDI_POST :
 363                         usb_ia_post_detach(usb_ia, usba_get_ifno(rdip),
 364                             (struct detachspec *)arg);
 365                         break;
 366                 }
 367 
 368                 break;
 369         default:
 370                 /* pass to root hub to handle */
 371                 return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
 372         }
 373 
 374         return (DDI_SUCCESS);
 375 }
 376 
 377 
 378 /*
 379  * bus enumeration entry points
 380  */
 381 static int
 382 usb_ia_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
 383     void *arg, dev_info_t **child)
 384 {
 385         int             rval, circ;
 386         usb_ia_t        *usb_ia = usb_ia_obtain_state(dip);
 387 
 388         USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
 389             "usb_ia_bus_config: op=%d", op);
 390 
 391         if (usb_ia_bus_config_debug) {
 392                 flag |= NDI_DEVI_DEBUG;
 393         }
 394 
 395         ndi_devi_enter(dip, &circ);
 396 
 397         /* enumerate each interface below us */
 398         mutex_enter(&usb_ia->ia_mutex);
 399         usb_ia_create_children(usb_ia);
 400         mutex_exit(&usb_ia->ia_mutex);
 401 
 402         rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
 403         ndi_devi_exit(dip, circ);
 404 
 405         return (rval);
 406 }
 407 
 408 
 409 static int
 410 usb_ia_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
 411     void *arg)
 412 {
 413         usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
 414 
 415         dev_info_t      *cdip, *mdip;
 416         int             interface, circular_count;
 417         int             rval = NDI_SUCCESS;
 418 
 419         USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
 420             "usb_ia_bus_unconfig: op=%d", op);
 421 
 422         if (usb_ia_bus_config_debug) {
 423                 flag |= NDI_DEVI_DEBUG;
 424         }
 425 
 426         /*
 427          * first offline and if offlining successful, then
 428          * remove children
 429          */
 430         if (op == BUS_UNCONFIG_ALL) {
 431                 flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
 432         }
 433 
 434         ndi_devi_enter(dip, &circular_count);
 435         rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
 436 
 437         if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
 438             (flag & NDI_AUTODETACH) == 0) {
 439                 flag |= NDI_DEVI_REMOVE;
 440                 rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
 441         }
 442 
 443         /* update children's list */
 444         mutex_enter(&usb_ia->ia_mutex);
 445         for (interface = 0; usb_ia->ia_children_dips &&
 446             (interface < usb_ia->ia_n_ifs); interface++) {
 447                 mdip = usb_ia->ia_children_dips[interface];
 448 
 449                 /* now search if this dip still exists */
 450                 for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); )
 451                         cdip = ddi_get_next_sibling(cdip);
 452 
 453                 if (cdip != mdip) {
 454                         /* we lost the dip on this interface */
 455                         usb_ia->ia_children_dips[interface] = NULL;
 456                 } else if (cdip) {
 457                         /*
 458                          * keep in DS_INITALIZED to prevent parent
 459                          * from detaching
 460                          */
 461                         (void) ddi_initchild(ddi_get_parent(cdip), cdip);
 462                 }
 463         }
 464         mutex_exit(&usb_ia->ia_mutex);
 465 
 466         ndi_devi_exit(dip, circular_count);
 467 
 468         USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
 469             "usb_ia_bus_config: rval=%d", rval);
 470 
 471         return (rval);
 472 }
 473 
 474 
 475 /* power entry point */
 476 /* ARGSUSED */
 477 static int
 478 usb_ia_power(dev_info_t *dip, int comp, int level)
 479 {
 480         usb_ia_t                *usb_ia;
 481         usb_common_power_t      *pm;
 482         int                     rval = DDI_FAILURE;
 483 
 484         usb_ia = usb_ia_obtain_state(dip);
 485 
 486         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
 487             "usb_ia_power: Begin: usb_ia = %p, level = %d",
 488             (void *)usb_ia, level);
 489 
 490         mutex_enter(&usb_ia->ia_mutex);
 491         pm = usb_ia->ia_pm;
 492 
 493         /* check if we are transitioning to a legal power level */
 494         if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) {
 495                 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
 496                     "usb_ia_power: illegal power level = %d "
 497                     "uc_pwr_states = %x", level, pm->uc_pwr_states);
 498 
 499                 mutex_exit(&usb_ia->ia_mutex);
 500 
 501                 return (rval);
 502         }
 503 
 504         rval = usba_common_power(dip, &(pm->uc_current_power),
 505             &(usb_ia->ia_dev_state), level);
 506 
 507         mutex_exit(&usb_ia->ia_mutex);
 508 
 509         return (rval);
 510 }
 511 
 512 /*
 513  * attach/resume entry point
 514  */
 515 static int
 516 usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 517 {
 518         int             instance = ddi_get_instance(dip);
 519         usb_ia_t        *usb_ia = NULL;
 520         uint_t          n_ifs;
 521         size_t          size;
 522 
 523         switch (cmd) {
 524         case DDI_ATTACH:
 525 
 526                 break;
 527         case DDI_RESUME:
 528                 usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
 529                 (void) usb_ia_restore_device_state(dip, usb_ia);
 530 
 531                 return (DDI_SUCCESS);
 532         default:
 533 
 534                 return (DDI_FAILURE);
 535         }
 536 
 537         /*
 538          * Attach:
 539          *
 540          * Allocate soft state and initialize
 541          */
 542         if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) {
 543                 goto fail;
 544         }
 545 
 546         usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
 547         if (usb_ia == NULL) {
 548 
 549                 goto fail;
 550         }
 551 
 552         /* allocate handle for logging of messages */
 553         usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia",
 554             &usb_ia_errlevel,
 555             &usb_ia_errmask, &usb_ia_instance_debug,
 556             0);
 557 
 558         usb_ia->ia_dip       = dip;
 559         usb_ia->ia_instance = instance;
 560         usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 561             DDI_PROP_DONTPASS, "interface", -1);
 562         usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 563             DDI_PROP_DONTPASS, "interface-count", -1);
 564 
 565         if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) {
 566                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 567                     "interface-association property failed");
 568 
 569                 goto fail;
 570         }
 571 
 572         /* attach client driver to USBA */
 573         if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
 574                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 575                     "usb_client_attach failed");
 576                 goto fail;
 577         }
 578         if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE,
 579             0) != USB_SUCCESS) {
 580                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 581                     "usb_get_dev_data failed");
 582                 goto fail;
 583         }
 584 
 585         mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER,
 586             usb_ia->ia_dev_data->dev_iblock_cookie);
 587 
 588         usb_free_dev_data(dip, usb_ia->ia_dev_data);
 589         usb_ia->ia_dev_data = NULL;
 590 
 591         usb_ia->ia_init_state |= USB_IA_LOCK_INIT;
 592 
 593         if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance,
 594             DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
 595                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 596                     "cannot create devctl minor node");
 597                 goto fail;
 598         }
 599 
 600         usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED;
 601 
 602         /*
 603          * allocate array for keeping track of child dips
 604          */
 605         n_ifs = usb_ia->ia_n_ifs;
 606         usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
 607 
 608         usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP);
 609         usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
 610             KM_SLEEP);
 611         /*
 612          * Event handling: definition and registration
 613          * get event handle for events that we have defined
 614          */
 615         (void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl,
 616             NDI_SLEEP);
 617 
 618         /* bind event set to the handle */
 619         if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events,
 620             NDI_SLEEP)) {
 621                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 622                     "usb_ia_attach: binding event set failed");
 623 
 624                 goto fail;
 625         }
 626 
 627         usb_ia->ia_dev_state = USB_DEV_ONLINE;
 628 
 629         /*
 630          * now create components to power manage this device
 631          * before attaching children
 632          */
 633         usb_ia_create_pm_components(dip, usb_ia);
 634 
 635         /* event registration for events from our parent */
 636         usba_common_register_events(dip, n_ifs, usb_ia_event_cb);
 637 
 638         usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED;
 639 
 640         ddi_report_dev(dip);
 641 
 642         return (DDI_SUCCESS);
 643 
 644 fail:
 645         USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach",
 646             instance);
 647 
 648         if (usb_ia) {
 649                 (void) usb_ia_cleanup(usb_ia);
 650         }
 651 
 652         return (DDI_FAILURE);
 653 }
 654 
 655 
 656 /* detach or suspend this instance */
 657 static int
 658 usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 659 {
 660         usb_ia_t        *usb_ia = usb_ia_obtain_state(dip);
 661 
 662         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 663             "usb_ia_detach: cmd = 0x%x", cmd);
 664 
 665         switch (cmd) {
 666         case DDI_DETACH:
 667 
 668                 return (usb_ia_cleanup(usb_ia));
 669         case DDI_SUSPEND:
 670                 /* nothing to do */
 671                 mutex_enter(&usb_ia->ia_mutex);
 672                 usb_ia->ia_dev_state = USB_DEV_SUSPENDED;
 673                 mutex_exit(&usb_ia->ia_mutex);
 674 
 675                 return (DDI_SUCCESS);
 676         default:
 677 
 678                 return (DDI_FAILURE);
 679         }
 680 
 681         _NOTE(NOT_REACHED)
 682         /* NOTREACHED */
 683 }
 684 
 685 
 686 /*
 687  * usb_ia_cleanup:
 688  *      cleanup usb_ia and deallocate. this function is called for
 689  *      handling attach failures and detaching including dynamic
 690  *      reconfiguration
 691  */
 692 /*ARGSUSED*/
 693 static int
 694 usb_ia_cleanup(usb_ia_t *usb_ia)
 695 {
 696         usb_common_power_t      *iapm;
 697         int                     rval;
 698         dev_info_t      *dip = usb_ia->ia_dip;
 699 
 700         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 701             "usb_ia_cleanup:");
 702 
 703         if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) {
 704 
 705                 goto done;
 706         }
 707 
 708         /*
 709          * deallocate events, if events are still registered
 710          * (ie. children still attached) then we have to fail the detach
 711          */
 712         if (usb_ia->ia_ndi_event_hdl &&
 713             (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) {
 714 
 715                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 716                     "usb_ia_cleanup: ndi_event_free_hdl failed");
 717 
 718                 return (DDI_FAILURE);
 719         }
 720 
 721         /*
 722          * Disable the event callbacks, after this point, event
 723          * callbacks will never get called. Note we shouldn't hold
 724          * mutex while unregistering events because there may be a
 725          * competing event callback thread. Event callbacks are done
 726          * with ndi mutex held and this can cause a potential deadlock.
 727          * Note that cleanup can't fail after deregistration of events.
 728          */
 729         if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) {
 730 
 731                 usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs);
 732         }
 733 
 734         iapm = usb_ia->ia_pm;
 735 
 736         mutex_enter(&usb_ia->ia_mutex);
 737 
 738         if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) {
 739 
 740                 mutex_exit(&usb_ia->ia_mutex);
 741 
 742                 (void) pm_busy_component(dip, 0);
 743                 if (iapm->uc_wakeup_enabled) {
 744 
 745                         /* First bring the device to full power */
 746                         (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
 747 
 748                         rval = usb_handle_remote_wakeup(dip,
 749                             USB_REMOTE_WAKEUP_DISABLE);
 750 
 751                         if (rval != DDI_SUCCESS) {
 752                                 USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
 753                                     usb_ia->ia_log_handle,
 754                                     "usb_cleanup: disable remote "
 755                                     "wakeup failed, rval=%d", rval);
 756                         }
 757                 }
 758 
 759                 (void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF);
 760                 (void) pm_idle_component(dip, 0);
 761         } else {
 762                 mutex_exit(&usb_ia->ia_mutex);
 763         }
 764 
 765         if (iapm) {
 766                 kmem_free(iapm, sizeof (usb_common_power_t));
 767         }
 768 
 769         /* free children list */
 770         if (usb_ia->ia_children_dips) {
 771                 kmem_free(usb_ia->ia_children_dips,
 772                     usb_ia->ia_cd_list_length);
 773         }
 774 
 775         if (usb_ia->ia_child_events) {
 776                 kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) *
 777                     usb_ia->ia_n_ifs);
 778         }
 779 
 780         if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) {
 781                 ddi_remove_minor_node(dip, NULL);
 782         }
 783 
 784         mutex_destroy(&usb_ia->ia_mutex);
 785 
 786 done:
 787         usb_client_detach(dip, usb_ia->ia_dev_data);
 788 
 789         usb_free_log_hdl(usb_ia->ia_log_handle);
 790         ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip));
 791 
 792         ddi_prop_remove_all(dip);
 793 
 794         return (DDI_SUCCESS);
 795 }
 796 
 797 /*
 798  * usb_ia_create_children:
 799  */
 800 static void
 801 usb_ia_create_children(usb_ia_t *usb_ia)
 802 {
 803         usba_device_t           *usba_device;
 804         uint_t                  n_ifs, first_if;
 805         uint_t                  i;
 806         dev_info_t              *cdip;
 807 
 808         usba_device = usba_get_usba_device(usb_ia->ia_dip);
 809 
 810         USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
 811             "usb_ia_attach_child_drivers: port = %d, address = %d",
 812             usba_device->usb_port, usba_device->usb_addr);
 813 
 814         n_ifs = usb_ia->ia_n_ifs;
 815         first_if = usb_ia->ia_first_if;
 816 
 817         /*
 818          * create all children if not already present
 819          */
 820         for (i = 0; i < n_ifs; i++) {
 821                 if (usb_ia->ia_children_dips[i] != NULL) {
 822 
 823                         continue;
 824                 }
 825 
 826                 mutex_exit(&usb_ia->ia_mutex);
 827                 cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i);
 828                 mutex_enter(&usb_ia->ia_mutex);
 829 
 830                 if (cdip != NULL) {
 831                         (void) usba_bind_driver(cdip);
 832                         usb_ia->ia_children_dips[i] = cdip;
 833                 }
 834         }
 835 
 836 }
 837 
 838 
 839 /*
 840  * event support
 841  */
 842 static int
 843 usb_ia_busop_get_eventcookie(dev_info_t *dip,
 844         dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
 845 {
 846         usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
 847 
 848         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 849             "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
 850             "event=%s", (void *)dip, (void *)rdip, eventname);
 851         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 852             "(dip=%s%d rdip=%s%d)",
 853             ddi_driver_name(dip), ddi_get_instance(dip),
 854             ddi_driver_name(rdip), ddi_get_instance(rdip));
 855 
 856         /* return event cookie, iblock cookie, and level */
 857         return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl,
 858             rdip, eventname, cookie, NDI_EVENT_NOPASS));
 859 }
 860 
 861 
 862 static int
 863 usb_ia_busop_add_eventcall(dev_info_t *dip,
 864         dev_info_t *rdip,
 865         ddi_eventcookie_t cookie,
 866         void (*callback)(dev_info_t *dip,
 867             ddi_eventcookie_t cookie, void *arg,
 868             void *bus_impldata),
 869         void *arg, ddi_callback_id_t *cb_id)
 870 {
 871         int     ifno;
 872         usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
 873 
 874         mutex_enter(&usb_ia->ia_mutex);
 875         ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if;
 876         mutex_exit(&usb_ia->ia_mutex);
 877 
 878         if (ifno < 0) {
 879                 ifno = 0;
 880         }
 881 
 882         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 883             "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p "
 884             "cookie=0x%p, cb=0x%p, arg=0x%p",
 885             (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
 886         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 887             "(dip=%s%d rdip=%s%d event=%s)",
 888             ddi_driver_name(dip), ddi_get_instance(dip),
 889             ddi_driver_name(rdip), ddi_get_instance(rdip),
 890             ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
 891 
 892         /* Set flag on children registering events */
 893         switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) {
 894         case USBA_EVENT_TAG_HOT_REMOVAL:
 895                 mutex_enter(&usb_ia->ia_mutex);
 896                 usb_ia->ia_child_events[ifno] |=
 897                     USB_IA_CHILD_EVENT_DISCONNECT;
 898                 mutex_exit(&usb_ia->ia_mutex);
 899 
 900                 break;
 901         case USBA_EVENT_TAG_PRE_SUSPEND:
 902                 mutex_enter(&usb_ia->ia_mutex);
 903                 usb_ia->ia_child_events[ifno] |=
 904                     USB_IA_CHILD_EVENT_PRESUSPEND;
 905                 mutex_exit(&usb_ia->ia_mutex);
 906 
 907                 break;
 908         default:
 909 
 910                 break;
 911         }
 912         /* add callback (perform registration) */
 913         return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl,
 914             rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
 915 }
 916 
 917 
 918 static int
 919 usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
 920 {
 921         usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
 922         ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
 923 
 924         ASSERT(cb);
 925 
 926         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 927             "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
 928             "cookie=0x%p", (void *)dip, (void *)cb->ndi_evtcb_dip,
 929             (void *)cb->ndi_evtcb_cookie);
 930         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 931             "(dip=%s%d rdip=%s%d event=%s)",
 932             ddi_driver_name(dip), ddi_get_instance(dip),
 933             ddi_driver_name(cb->ndi_evtcb_dip),
 934             ddi_get_instance(cb->ndi_evtcb_dip),
 935             ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl,
 936             cb->ndi_evtcb_cookie));
 937 
 938         /* remove event registration from our event set */
 939         return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id));
 940 }
 941 
 942 
 943 static int
 944 usb_ia_busop_post_event(dev_info_t *dip,
 945         dev_info_t *rdip,
 946         ddi_eventcookie_t cookie,
 947         void *bus_impldata)
 948 {
 949         usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
 950 
 951         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 952             "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p "
 953             "cookie=0x%p, impl=0x%p",
 954             (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
 955         USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 956             "(dip=%s%d rdip=%s%d event=%s)",
 957             ddi_driver_name(dip), ddi_get_instance(dip),
 958             ddi_driver_name(rdip), ddi_get_instance(rdip),
 959             ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
 960 
 961         /* post event to all children registered for this event */
 962         return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip,
 963             cookie, bus_impldata));
 964 }
 965 
 966 
 967 /*
 968  * usb_ia_restore_device_state
 969  *      set the original configuration of the device
 970  */
 971 static int
 972 usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia)
 973 {
 974         usb_common_power_t      *iapm;
 975 
 976         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
 977             "usb_ia_restore_device_state: usb_ia = %p", (void *)usb_ia);
 978 
 979         mutex_enter(&usb_ia->ia_mutex);
 980         iapm = usb_ia->ia_pm;
 981         mutex_exit(&usb_ia->ia_mutex);
 982 
 983         /* First bring the device to full power */
 984         (void) pm_busy_component(dip, 0);
 985         (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
 986 
 987         if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0,
 988             DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
 989 
 990                 /* change the device state from suspended to disconnected */
 991                 mutex_enter(&usb_ia->ia_mutex);
 992                 usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
 993                 mutex_exit(&usb_ia->ia_mutex);
 994                 (void) pm_idle_component(dip, 0);
 995 
 996                 return (USB_FAILURE);
 997         }
 998 
 999         /*
1000          * if the device had remote wakeup earlier,
1001          * enable it again
1002          */
1003         if (iapm->uc_wakeup_enabled) {
1004                 (void) usb_handle_remote_wakeup(usb_ia->ia_dip,
1005                     USB_REMOTE_WAKEUP_ENABLE);
1006         }
1007 
1008         mutex_enter(&usb_ia->ia_mutex);
1009         usb_ia->ia_dev_state = USB_DEV_ONLINE;
1010         mutex_exit(&usb_ia->ia_mutex);
1011 
1012         (void) pm_idle_component(dip, 0);
1013 
1014         return (USB_SUCCESS);
1015 }
1016 
1017 
1018 /*
1019  * usb_ia_event_cb()
1020  *      handle disconnect and connect events
1021  */
1022 static void
1023 usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
1024         void *arg, void *bus_impldata)
1025 {
1026         int             i, tag;
1027         usb_ia_t        *usb_ia = usb_ia_obtain_state(dip);
1028         dev_info_t      *child_dip;
1029         ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
1030 
1031         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
1032             "usb_ia_event_cb: dip=0x%p, cookie=0x%p, "
1033             "arg=0x%p, impl=0x%p",
1034             (void *)dip, (void *)cookie, arg, bus_impldata);
1035         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
1036             "(dip=%s%d event=%s)",
1037             ddi_driver_name(dip), ddi_get_instance(dip),
1038             ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
1039 
1040         tag = NDI_EVENT_TAG(cookie);
1041         rm_cookie = ndi_event_tag_to_cookie(
1042             usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
1043         suspend_cookie = ndi_event_tag_to_cookie(
1044             usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
1045         ins_cookie = ndi_event_tag_to_cookie(
1046             usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
1047         resume_cookie = ndi_event_tag_to_cookie(
1048             usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
1049 
1050         mutex_enter(&usb_ia->ia_mutex);
1051         switch (tag) {
1052         case USBA_EVENT_TAG_HOT_REMOVAL:
1053                 if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) {
1054                         USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
1055                             usb_ia->ia_log_handle,
1056                             "usb_ia_event_cb: Device already disconnected");
1057                 } else {
1058                         /* we are disconnected so set our state now */
1059                         usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
1060                         for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1061                                 usb_ia->ia_child_events[i] &= ~
1062                                     USB_IA_CHILD_EVENT_DISCONNECT;
1063                         }
1064                         mutex_exit(&usb_ia->ia_mutex);
1065 
1066                         /* pass disconnect event to all the children */
1067                         (void) ndi_event_run_callbacks(
1068                             usb_ia->ia_ndi_event_hdl, NULL,
1069                             rm_cookie, bus_impldata);
1070 
1071                         mutex_enter(&usb_ia->ia_mutex);
1072                 }
1073                 break;
1074         case USBA_EVENT_TAG_PRE_SUSPEND:
1075                 /* set our state *after* suspending children */
1076                 mutex_exit(&usb_ia->ia_mutex);
1077 
1078                 /* pass pre_suspend event to all the children */
1079                 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
1080                     NULL, suspend_cookie, bus_impldata);
1081 
1082                 mutex_enter(&usb_ia->ia_mutex);
1083                 for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1084                         usb_ia->ia_child_events[i] &= ~
1085                             USB_IA_CHILD_EVENT_PRESUSPEND;
1086                 }
1087                 break;
1088         case USBA_EVENT_TAG_HOT_INSERTION:
1089                 mutex_exit(&usb_ia->ia_mutex);
1090                 if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) {
1091 
1092                         /*
1093                          * Check to see if this child has missed the disconnect
1094                          * event before it registered for event cb
1095                          */
1096                         mutex_enter(&usb_ia->ia_mutex);
1097                         for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1098                                 if (usb_ia->ia_child_events[i] &
1099                                     USB_IA_CHILD_EVENT_DISCONNECT) {
1100                                         usb_ia->ia_child_events[i] &=
1101                                             ~USB_IA_CHILD_EVENT_DISCONNECT;
1102                                         child_dip =
1103                                             usb_ia->ia_children_dips[i];
1104                                         mutex_exit(&usb_ia->ia_mutex);
1105 
1106                                         /* post the missed disconnect */
1107                                         (void) ndi_event_do_callback(
1108                                             usb_ia->ia_ndi_event_hdl,
1109                                             child_dip,
1110                                             rm_cookie,
1111                                             bus_impldata);
1112                                         mutex_enter(&usb_ia->ia_mutex);
1113                                 }
1114                         }
1115                         mutex_exit(&usb_ia->ia_mutex);
1116 
1117                         /* pass reconnect event to all the children */
1118                         (void) ndi_event_run_callbacks(
1119                             usb_ia->ia_ndi_event_hdl, NULL,
1120                             ins_cookie, bus_impldata);
1121 
1122                 }
1123                 mutex_enter(&usb_ia->ia_mutex);
1124                 break;
1125         case USBA_EVENT_TAG_POST_RESUME:
1126                 /*
1127                  * Check to see if this child has missed the pre-suspend
1128                  * event before it registered for event cb
1129                  */
1130                 for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1131                         if (usb_ia->ia_child_events[i] &
1132                             USB_IA_CHILD_EVENT_PRESUSPEND) {
1133                                 usb_ia->ia_child_events[i] &=
1134                                     ~USB_IA_CHILD_EVENT_PRESUSPEND;
1135                                 child_dip = usb_ia->ia_children_dips[i];
1136                                 mutex_exit(&usb_ia->ia_mutex);
1137 
1138                                 /* post the missed pre-suspend event */
1139                                 (void) ndi_event_do_callback(
1140                                     usb_ia->ia_ndi_event_hdl,
1141                                     child_dip, suspend_cookie,
1142                                     bus_impldata);
1143                                 mutex_enter(&usb_ia->ia_mutex);
1144                         }
1145                 }
1146                 mutex_exit(&usb_ia->ia_mutex);
1147 
1148                 /* pass post_resume event to all the children */
1149                 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
1150                     NULL, resume_cookie, bus_impldata);
1151 
1152                 mutex_enter(&usb_ia->ia_mutex);
1153                 break;
1154         }
1155         mutex_exit(&usb_ia->ia_mutex);
1156 
1157 }
1158 
1159 /*
1160  * create the pm components required for power management
1161  */
1162 static void
1163 usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia)
1164 {
1165         usb_common_power_t      *iapm;
1166         uint_t                  pwr_states;
1167 
1168         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1169             "usb_ia_create_pm_components: Begin");
1170 
1171         /* Allocate the PM state structure */
1172         iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
1173 
1174         mutex_enter(&usb_ia->ia_mutex);
1175         usb_ia->ia_pm = iapm;
1176         iapm->uc_usb_statep = usb_ia;
1177         iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
1178         iapm->uc_current_power = USB_DEV_OS_FULL_PWR;
1179         mutex_exit(&usb_ia->ia_mutex);
1180 
1181         /*
1182          * By not enabling parental notification, PM enforces
1183          * "strict parental dependency" meaning, usb_ia won't
1184          * power off until any of its children are in full power.
1185          */
1186 
1187         /*
1188          * there are 3 scenarios:
1189          * 1. a well behaved device should have remote wakeup
1190          * at interface and device level. If the interface
1191          * wakes up, usb_ia will wake up
1192          * 2. if the device doesn't have remote wake up and
1193          * the interface has, PM will still work, ie.
1194          * the interfaces wakes up and usb_ia wakes up
1195          * 3. if neither the interface nor device has remote
1196          * wakeup, the interface will wake up when it is opened
1197          * and goes to sleep after being closed for a while
1198          * In this case usb_ia should also go to sleep shortly
1199          * thereafter
1200          * In all scenarios it doesn't really matter whether
1201          * remote wakeup at the device level is enabled or not
1202          * but we do it anyways
1203          */
1204         if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
1205             USB_SUCCESS) {
1206                 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1207                     "usb_ia_create_pm_components: "
1208                     "Remote Wakeup Enabled");
1209                 iapm->uc_wakeup_enabled = 1;
1210         }
1211 
1212         if (usb_create_pm_components(dip, &pwr_states) ==
1213             USB_SUCCESS) {
1214                 iapm->uc_pwr_states = (uint8_t)pwr_states;
1215                 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1216         }
1217 
1218         USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1219             "usb_ia_create_pm_components: End");
1220 }
1221 
1222 
1223 /*
1224  * usb_ia_obtain_state:
1225  */
1226 static usb_ia_t *
1227 usb_ia_obtain_state(dev_info_t *dip)
1228 {
1229         int instance = ddi_get_instance(dip);
1230         usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance);
1231 
1232         ASSERT(statep != NULL);
1233 
1234         return (statep);
1235 }