xref: /onnv-gate/usr/src/uts/common/io/usb/usb_ia/usb_ia.c (revision 8688:200c0876aa34)
13341Sgc161489 /*
23341Sgc161489  * CDDL HEADER START
33341Sgc161489  *
43341Sgc161489  * The contents of this file are subject to the terms of the
53341Sgc161489  * Common Development and Distribution License (the "License").
63341Sgc161489  * You may not use this file except in compliance with the License.
73341Sgc161489  *
83341Sgc161489  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93341Sgc161489  * or http://www.opensolaris.org/os/licensing.
103341Sgc161489  * See the License for the specific language governing permissions
113341Sgc161489  * and limitations under the License.
123341Sgc161489  *
133341Sgc161489  * When distributing Covered Code, include this CDDL HEADER in each
143341Sgc161489  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153341Sgc161489  * If applicable, add the following below this CDDL HEADER, with the
163341Sgc161489  * fields enclosed by brackets "[]" replaced with your own identifying
173341Sgc161489  * information: Portions Copyright [yyyy] [name of copyright owner]
183341Sgc161489  *
193341Sgc161489  * CDDL HEADER END
203341Sgc161489  */
213341Sgc161489 /*
22*8688SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233341Sgc161489  * Use is subject to license terms.
243341Sgc161489  */
253341Sgc161489 
263341Sgc161489 
273341Sgc161489 /*
283341Sgc161489  * usb interface association driver
293341Sgc161489  *
303341Sgc161489  *	this driver attempts to the interface association node and
313341Sgc161489  *	creates/manages child nodes for the included interfaces.
323341Sgc161489  */
333341Sgc161489 
343341Sgc161489 #if defined(lint) && !defined(DEBUG)
353341Sgc161489 #define	DEBUG	1
363341Sgc161489 #endif
373341Sgc161489 #include <sys/usb/usba/usbai_version.h>
383341Sgc161489 #include <sys/usb/usba.h>
393341Sgc161489 #include <sys/usb/usba/usba_types.h>
403341Sgc161489 #include <sys/usb/usba/usba_impl.h>
413341Sgc161489 #include <sys/usb/usb_ia/usb_iavar.h>
423341Sgc161489 
433341Sgc161489 /* Debugging support */
443341Sgc161489 uint_t usb_ia_errlevel = USB_LOG_L4;
453341Sgc161489 uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL;
463341Sgc161489 uint_t usb_ia_instance_debug = (uint_t)-1;
473341Sgc161489 uint_t usb_ia_bus_config_debug = 0;
483341Sgc161489 
493341Sgc161489 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel))
503341Sgc161489 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask))
513341Sgc161489 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug))
523341Sgc161489 
533341Sgc161489 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
543341Sgc161489 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
553341Sgc161489 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
563341Sgc161489 
573341Sgc161489 static struct cb_ops usb_ia_cb_ops = {
583341Sgc161489 	nodev,		/* open */
593341Sgc161489 	nodev,		/* close */
603341Sgc161489 	nodev,		/* strategy */
613341Sgc161489 	nodev,		/* print */
623341Sgc161489 	nodev,		/* dump */
633341Sgc161489 	nodev,		/* read */
643341Sgc161489 	nodev,		/* write */
653341Sgc161489 	nodev,		/* ioctl */
663341Sgc161489 	nodev,		/* devmap */
673341Sgc161489 	nodev,		/* mmap */
683341Sgc161489 	nodev,		/* segmap */
693341Sgc161489 	nochpoll,	/* poll */
703341Sgc161489 	ddi_prop_op,	/* prop_op */
713341Sgc161489 	NULL,		/* aread */
723341Sgc161489 	D_MP
733341Sgc161489 };
743341Sgc161489 
753341Sgc161489 static int usb_ia_busop_get_eventcookie(dev_info_t *dip,
763341Sgc161489 			dev_info_t *rdip,
773341Sgc161489 			char *eventname,
783341Sgc161489 			ddi_eventcookie_t *cookie);
793341Sgc161489 static int usb_ia_busop_add_eventcall(dev_info_t *dip,
803341Sgc161489 			dev_info_t *rdip,
813341Sgc161489 			ddi_eventcookie_t cookie,
823341Sgc161489 			void (*callback)(dev_info_t *dip,
833341Sgc161489 				ddi_eventcookie_t cookie, void *arg,
843341Sgc161489 				void *bus_impldata),
853341Sgc161489 			void *arg, ddi_callback_id_t *cb_id);
863341Sgc161489 static int usb_ia_busop_remove_eventcall(dev_info_t *dip,
873341Sgc161489 			ddi_callback_id_t cb_id);
883341Sgc161489 static int usb_ia_busop_post_event(dev_info_t *dip,
893341Sgc161489 			dev_info_t *rdip,
903341Sgc161489 			ddi_eventcookie_t cookie,
913341Sgc161489 			void *bus_impldata);
923341Sgc161489 static int usb_ia_bus_config(dev_info_t *dip,
933341Sgc161489 			uint_t flag,
943341Sgc161489 			ddi_bus_config_op_t op,
953341Sgc161489 			void *arg,
963341Sgc161489 			dev_info_t **child);
973341Sgc161489 static int usb_ia_bus_unconfig(dev_info_t *dip,
983341Sgc161489 			uint_t flag,
993341Sgc161489 			ddi_bus_config_op_t op,
1003341Sgc161489 			void *arg);
1013341Sgc161489 
1023341Sgc161489 /*
1033341Sgc161489  * autoconfiguration data and routines.
1043341Sgc161489  */
1053341Sgc161489 static int	usb_ia_info(dev_info_t *, ddi_info_cmd_t,
1063341Sgc161489 				void *, void **);
1073341Sgc161489 static int	usb_ia_attach(dev_info_t *, ddi_attach_cmd_t);
1083341Sgc161489 static int	usb_ia_detach(dev_info_t *, ddi_detach_cmd_t);
1093341Sgc161489 
1103341Sgc161489 /* other routines */
1113341Sgc161489 static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *);
1123341Sgc161489 static int usb_ia_bus_ctl(dev_info_t *, dev_info_t	*,
1133341Sgc161489 				ddi_ctl_enum_t, void *, void *);
1143341Sgc161489 static int usb_ia_power(dev_info_t *, int, int);
1153341Sgc161489 static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *);
1163341Sgc161489 static usb_ia_t  *usb_ia_obtain_state(dev_info_t *);
1173341Sgc161489 static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
1183341Sgc161489 
1193341Sgc161489 /* prototypes */
1203341Sgc161489 static void usb_ia_create_children(usb_ia_t *);
1213341Sgc161489 static int usb_ia_cleanup(usb_ia_t *);
1223341Sgc161489 
1233341Sgc161489 /*
1243341Sgc161489  * Busops vector
1253341Sgc161489  */
1263341Sgc161489 static struct bus_ops usb_ia_busops = {
1273341Sgc161489 	BUSO_REV,
1283341Sgc161489 	nullbusmap,			/* bus_map */
1293341Sgc161489 	NULL,				/* bus_get_intrspec */
1303341Sgc161489 	NULL,				/* bus_add_intrspec */
1313341Sgc161489 	NULL,				/* bus_remove_intrspec */
1323341Sgc161489 	NULL,				/* XXXX bus_map_fault */
1333341Sgc161489 	ddi_dma_map,			/* bus_dma_map */
1343341Sgc161489 	ddi_dma_allochdl,
1353341Sgc161489 	ddi_dma_freehdl,
1363341Sgc161489 	ddi_dma_bindhdl,
1373341Sgc161489 	ddi_dma_unbindhdl,
1383341Sgc161489 	ddi_dma_flush,
1393341Sgc161489 	ddi_dma_win,
1403341Sgc161489 	ddi_dma_mctl,			/* bus_dma_ctl */
1413341Sgc161489 	usb_ia_bus_ctl,		/* bus_ctl */
1423341Sgc161489 	ddi_bus_prop_op,		/* bus_prop_op */
1433341Sgc161489 	usb_ia_busop_get_eventcookie,
1443341Sgc161489 	usb_ia_busop_add_eventcall,
1453341Sgc161489 	usb_ia_busop_remove_eventcall,
1463341Sgc161489 	usb_ia_busop_post_event,	/* bus_post_event */
1473341Sgc161489 	NULL,				/* bus_intr_ctl */
1483341Sgc161489 	usb_ia_bus_config,		/* bus_config */
1493341Sgc161489 	usb_ia_bus_unconfig,		/* bus_unconfig */
1503341Sgc161489 	NULL,				/* bus_fm_init */
1513341Sgc161489 	NULL,				/* bus_fm_fini */
1523341Sgc161489 	NULL,				/* bus_fm_access_enter */
1533341Sgc161489 	NULL,				/* bus_fm_access_exit */
1543341Sgc161489 	NULL				/* bus_power */
1553341Sgc161489 };
1563341Sgc161489 
1573341Sgc161489 
1583341Sgc161489 static struct dev_ops usb_ia_ops = {
1593341Sgc161489 	DEVO_REV,		/* devo_rev, */
1603341Sgc161489 	0,			/* refcnt  */
1613341Sgc161489 	usb_ia_info,		/* info */
1623341Sgc161489 	nulldev,		/* identify */
1633341Sgc161489 	nulldev,		/* probe */
1643341Sgc161489 	usb_ia_attach,		/* attach */
1653341Sgc161489 	usb_ia_detach,		/* detach */
1663341Sgc161489 	nodev,			/* reset */
1673341Sgc161489 	&usb_ia_cb_ops,	/* driver operations */
1683341Sgc161489 	&usb_ia_busops,	/* bus operations */
1697656SSherry.Moore@Sun.COM 	usb_ia_power,		/* power */
170*8688SRaymond.Chen@Sun.COM 	ddi_quiesce_not_needed,	/* devo_quiesce */
1713341Sgc161489 };
1723341Sgc161489 
1733341Sgc161489 static struct modldrv modldrv = {
1743341Sgc161489 	&mod_driverops, /* Type of module. This one is a driver */
1757425SGongtian.Zhao@Sun.COM 	"USB Interface Association Driver", /* Name of the module. */
1763341Sgc161489 	&usb_ia_ops,	/* driver ops */
1773341Sgc161489 };
1783341Sgc161489 
1793341Sgc161489 static struct modlinkage modlinkage = {
1803341Sgc161489 	MODREV_1, (void *)&modldrv, NULL
1813341Sgc161489 };
1823341Sgc161489 
1833341Sgc161489 #define	USB_IA_INITIAL_SOFT_SPACE 4
1843341Sgc161489 static	void	*usb_ia_statep;
1853341Sgc161489 
1863341Sgc161489 /*
1873341Sgc161489  * event definition
1883341Sgc161489  */
1893341Sgc161489 static ndi_event_definition_t usb_ia_ndi_event_defs[] = {
1903341Sgc161489 	{USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
1913341Sgc161489 						NDI_EVENT_POST_TO_ALL},
1923341Sgc161489 	{USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
1933341Sgc161489 						NDI_EVENT_POST_TO_ALL},
1943341Sgc161489 	{USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
1953341Sgc161489 						NDI_EVENT_POST_TO_ALL},
1963341Sgc161489 	{USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
1973341Sgc161489 						NDI_EVENT_POST_TO_ALL}
1983341Sgc161489 };
1993341Sgc161489 
2003341Sgc161489 #define	USB_IA_N_NDI_EVENTS \
2013341Sgc161489 	(sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t))
2023341Sgc161489 
2033341Sgc161489 static	ndi_event_set_t usb_ia_ndi_events = {
2043341Sgc161489 	NDI_EVENTS_REV1, USB_IA_N_NDI_EVENTS, usb_ia_ndi_event_defs};
2053341Sgc161489 
2063341Sgc161489 
2073341Sgc161489 /*
2083341Sgc161489  * standard driver entry points
2093341Sgc161489  */
2103341Sgc161489 int
_init(void)2113341Sgc161489 _init(void)
2123341Sgc161489 {
2133341Sgc161489 	int rval;
2143341Sgc161489 
2153341Sgc161489 	rval = ddi_soft_state_init(&usb_ia_statep, sizeof (struct usb_ia),
2163341Sgc161489 	    USB_IA_INITIAL_SOFT_SPACE);
2173341Sgc161489 	if (rval != 0) {
2183341Sgc161489 		return (rval);
2193341Sgc161489 	}
2203341Sgc161489 
2213341Sgc161489 	if ((rval = mod_install(&modlinkage)) != 0) {
2223341Sgc161489 		ddi_soft_state_fini(&usb_ia_statep);
2233341Sgc161489 		return (rval);
2243341Sgc161489 	}
2253341Sgc161489 
2263341Sgc161489 	return (rval);
2273341Sgc161489 }
2283341Sgc161489 
2293341Sgc161489 
2303341Sgc161489 int
_fini(void)2313341Sgc161489 _fini(void)
2323341Sgc161489 {
2333341Sgc161489 	int	rval;
2343341Sgc161489 
2353341Sgc161489 	rval = mod_remove(&modlinkage);
2363341Sgc161489 
2373341Sgc161489 	if (rval) {
2383341Sgc161489 		return (rval);
2393341Sgc161489 	}
2403341Sgc161489 
2413341Sgc161489 	ddi_soft_state_fini(&usb_ia_statep);
2423341Sgc161489 
2433341Sgc161489 	return (rval);
2443341Sgc161489 }
2453341Sgc161489 
2463341Sgc161489 
2473341Sgc161489 int
_info(struct modinfo * modinfop)2483341Sgc161489 _info(struct modinfo *modinfop)
2493341Sgc161489 {
2503341Sgc161489 	return (mod_info(&modlinkage, modinfop));
2513341Sgc161489 }
2523341Sgc161489 
2533341Sgc161489 
2543341Sgc161489 /*ARGSUSED*/
2553341Sgc161489 static int
usb_ia_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2563341Sgc161489 usb_ia_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2573341Sgc161489 {
2583341Sgc161489 	usb_ia_t	*usb_ia;
2593341Sgc161489 	int		instance = getminor((dev_t)arg);
2603341Sgc161489 	int		error = DDI_FAILURE;
2613341Sgc161489 
2623341Sgc161489 	switch (infocmd) {
2633341Sgc161489 	case DDI_INFO_DEVT2DEVINFO:
2643341Sgc161489 		if ((usb_ia = ddi_get_soft_state(usb_ia_statep,
2653341Sgc161489 		    instance)) != NULL) {
2663341Sgc161489 			*result = (void *)usb_ia->ia_dip;
2673341Sgc161489 			if (*result != NULL) {
2683341Sgc161489 				error = DDI_SUCCESS;
2693341Sgc161489 			}
2703341Sgc161489 		} else {
2713341Sgc161489 			*result = NULL;
2723341Sgc161489 		}
2733341Sgc161489 		break;
2743341Sgc161489 
2753341Sgc161489 	case DDI_INFO_DEVT2INSTANCE:
2763341Sgc161489 		*result = (void *)(intptr_t)instance;
2773341Sgc161489 		error = DDI_SUCCESS;
2783341Sgc161489 		break;
2793341Sgc161489 	default:
2803341Sgc161489 		break;
2813341Sgc161489 	}
2823341Sgc161489 
2833341Sgc161489 	return (error);
2843341Sgc161489 }
2853341Sgc161489 
2863341Sgc161489 
2873341Sgc161489 /*
2883341Sgc161489  * child  post attach/detach notification
2893341Sgc161489  */
2903341Sgc161489 static void
usb_ia_post_attach(usb_ia_t * usb_ia,uint8_t ifno,struct attachspec * as)2913341Sgc161489 usb_ia_post_attach(usb_ia_t *usb_ia, uint8_t ifno, struct attachspec *as)
2923341Sgc161489 {
2933341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
2943341Sgc161489 	    "usb_ia_post_attach: ifno = %d result = %d", ifno, as->result);
2953341Sgc161489 
2963341Sgc161489 }
2973341Sgc161489 
2983341Sgc161489 
2993341Sgc161489 static void
usb_ia_post_detach(usb_ia_t * usb_ia,uint8_t ifno,struct detachspec * ds)3003341Sgc161489 usb_ia_post_detach(usb_ia_t *usb_ia, uint8_t ifno, struct detachspec *ds)
3013341Sgc161489 {
3023341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
3033341Sgc161489 	    "usb_ia_post_detach: ifno = %d result = %d", ifno, ds->result);
3043341Sgc161489 
3053341Sgc161489 }
3063341Sgc161489 
3073341Sgc161489 
3083341Sgc161489 /*
3093341Sgc161489  * bus ctl support. we handle notifications here and the
3103341Sgc161489  * rest goes up to root hub/hcd
3113341Sgc161489  */
3123341Sgc161489 /*ARGSUSED*/
3133341Sgc161489 static int
usb_ia_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)3143341Sgc161489 usb_ia_bus_ctl(dev_info_t *dip,
3153341Sgc161489 	dev_info_t	*rdip,
3163341Sgc161489 	ddi_ctl_enum_t	op,
3173341Sgc161489 	void		*arg,
3183341Sgc161489 	void		*result)
3193341Sgc161489 {
3203341Sgc161489 	usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
3213341Sgc161489 	dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
3223341Sgc161489 	usb_ia_t  *usb_ia;
3233341Sgc161489 	struct attachspec *as;
3243341Sgc161489 	struct detachspec *ds;
3253341Sgc161489 
3263341Sgc161489 	usb_ia = usb_ia_obtain_state(dip);
3273341Sgc161489 
3283341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
3293341Sgc161489 	    "usb_ia_bus_ctl:\n\t"
3303341Sgc161489 	    "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
3316898Sfb209375 	    (void *)dip, (void *)rdip, op, arg);
3323341Sgc161489 
3333341Sgc161489 	switch (op) {
3343341Sgc161489 	case DDI_CTLOPS_ATTACH:
3353341Sgc161489 		as = (struct attachspec *)arg;
3363341Sgc161489 
3373341Sgc161489 		switch (as->when) {
3383341Sgc161489 		case DDI_PRE :
3393341Sgc161489 			/* nothing to do basically */
3403341Sgc161489 			USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
3413341Sgc161489 			    "DDI_PRE DDI_CTLOPS_ATTACH");
3423341Sgc161489 			break;
3433341Sgc161489 		case DDI_POST :
3443341Sgc161489 			usb_ia_post_attach(usb_ia, usba_get_ifno(rdip),
3453341Sgc161489 			    (struct attachspec *)arg);
3463341Sgc161489 			break;
3473341Sgc161489 		}
3483341Sgc161489 
3493341Sgc161489 		break;
3503341Sgc161489 	case DDI_CTLOPS_DETACH:
3513341Sgc161489 		ds = (struct detachspec *)arg;
3523341Sgc161489 
3533341Sgc161489 		switch (ds->when) {
3543341Sgc161489 		case DDI_PRE :
3553341Sgc161489 			/* nothing to do basically */
3563341Sgc161489 			USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
3573341Sgc161489 			    "DDI_PRE DDI_CTLOPS_DETACH");
3583341Sgc161489 			break;
3593341Sgc161489 		case DDI_POST :
3603341Sgc161489 			usb_ia_post_detach(usb_ia, usba_get_ifno(rdip),
3613341Sgc161489 			    (struct detachspec *)arg);
3623341Sgc161489 			break;
3633341Sgc161489 		}
3643341Sgc161489 
3653341Sgc161489 		break;
3663341Sgc161489 	default:
3673341Sgc161489 		/* pass to root hub to handle */
3683341Sgc161489 		return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
3693341Sgc161489 	}
3703341Sgc161489 
3713341Sgc161489 	return (DDI_SUCCESS);
3723341Sgc161489 }
3733341Sgc161489 
3743341Sgc161489 
3753341Sgc161489 /*
3763341Sgc161489  * bus enumeration entry points
3773341Sgc161489  */
3783341Sgc161489 static int
usb_ia_bus_config(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg,dev_info_t ** child)3793341Sgc161489 usb_ia_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
3803341Sgc161489     void *arg, dev_info_t **child)
3813341Sgc161489 {
3823341Sgc161489 	int		rval, circ;
3833341Sgc161489 	usb_ia_t	*usb_ia = usb_ia_obtain_state(dip);
3843341Sgc161489 
3853341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
3863341Sgc161489 	    "usb_ia_bus_config: op=%d", op);
3873341Sgc161489 
3883341Sgc161489 	if (usb_ia_bus_config_debug) {
3893341Sgc161489 		flag |= NDI_DEVI_DEBUG;
3903341Sgc161489 	}
3913341Sgc161489 
3923341Sgc161489 	ndi_devi_enter(dip, &circ);
3933341Sgc161489 
3943341Sgc161489 	/* enumerate each interface below us */
3953341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
3963341Sgc161489 	usb_ia_create_children(usb_ia);
3973341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
3983341Sgc161489 
3993341Sgc161489 	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
4003341Sgc161489 	ndi_devi_exit(dip, circ);
4013341Sgc161489 
4023341Sgc161489 	return (rval);
4033341Sgc161489 }
4043341Sgc161489 
4053341Sgc161489 
4063341Sgc161489 static int
usb_ia_bus_unconfig(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg)4073341Sgc161489 usb_ia_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
4083341Sgc161489     void *arg)
4093341Sgc161489 {
4103341Sgc161489 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
4113341Sgc161489 
4123341Sgc161489 	dev_info_t	*cdip, *mdip;
4133341Sgc161489 	int		interface, circular_count;
4143341Sgc161489 	int		rval = NDI_SUCCESS;
4153341Sgc161489 
4163341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
4173341Sgc161489 	    "usb_ia_bus_unconfig: op=%d", op);
4183341Sgc161489 
4193341Sgc161489 	if (usb_ia_bus_config_debug) {
4203341Sgc161489 		flag |= NDI_DEVI_DEBUG;
4213341Sgc161489 	}
4223341Sgc161489 
4233341Sgc161489 	/*
4243341Sgc161489 	 * first offline and if offlining successful, then
4253341Sgc161489 	 * remove children
4263341Sgc161489 	 */
4273341Sgc161489 	if (op == BUS_UNCONFIG_ALL) {
4283341Sgc161489 		flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
4293341Sgc161489 	}
4303341Sgc161489 
4313341Sgc161489 	ndi_devi_enter(dip, &circular_count);
4323341Sgc161489 	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
4333341Sgc161489 
4343341Sgc161489 	if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
4353341Sgc161489 	    (flag & NDI_AUTODETACH) == 0) {
4363341Sgc161489 		flag |= NDI_DEVI_REMOVE;
4373341Sgc161489 		rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
4383341Sgc161489 	}
4393341Sgc161489 
4403341Sgc161489 	/* update children's list */
4413341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
4423341Sgc161489 	for (interface = 0; usb_ia->ia_children_dips &&
4433341Sgc161489 	    (interface < usb_ia->ia_n_ifs); interface++) {
4443341Sgc161489 		mdip = usb_ia->ia_children_dips[interface];
4453341Sgc161489 
4463341Sgc161489 		/* now search if this dip still exists */
4476898Sfb209375 		for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); )
4486898Sfb209375 			cdip = ddi_get_next_sibling(cdip);
4493341Sgc161489 
4503341Sgc161489 		if (cdip != mdip) {
4513341Sgc161489 			/* we lost the dip on this interface */
4523341Sgc161489 			usb_ia->ia_children_dips[interface] = NULL;
4533341Sgc161489 		} else if (cdip) {
4543341Sgc161489 			/*
4553341Sgc161489 			 * keep in DS_INITALIZED to prevent parent
4563341Sgc161489 			 * from detaching
4573341Sgc161489 			 */
4583341Sgc161489 			(void) ddi_initchild(ddi_get_parent(cdip), cdip);
4593341Sgc161489 		}
4603341Sgc161489 	}
4613341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
4623341Sgc161489 
4633341Sgc161489 	ndi_devi_exit(dip, circular_count);
4643341Sgc161489 
4653341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
4663341Sgc161489 	    "usb_ia_bus_config: rval=%d", rval);
4673341Sgc161489 
4683341Sgc161489 	return (rval);
4693341Sgc161489 }
4703341Sgc161489 
4713341Sgc161489 
4723341Sgc161489 /* power entry point */
4733341Sgc161489 /* ARGSUSED */
4743341Sgc161489 static int
usb_ia_power(dev_info_t * dip,int comp,int level)4753341Sgc161489 usb_ia_power(dev_info_t *dip, int comp, int level)
4763341Sgc161489 {
4773341Sgc161489 	usb_ia_t		*usb_ia;
4783341Sgc161489 	usb_common_power_t	*pm;
4793341Sgc161489 	int			rval = DDI_FAILURE;
4803341Sgc161489 
4813341Sgc161489 	usb_ia = usb_ia_obtain_state(dip);
4823341Sgc161489 
4833341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
4846898Sfb209375 	    "usb_ia_power: Begin: usb_ia = %p, level = %d",
4856898Sfb209375 	    (void *)usb_ia, level);
4863341Sgc161489 
4873341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
4883341Sgc161489 	pm = usb_ia->ia_pm;
4893341Sgc161489 
4903341Sgc161489 	/* check if we are transitioning to a legal power level */
4913341Sgc161489 	if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) {
4923341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
4933341Sgc161489 		    "usb_ia_power: illegal power level = %d "
4943341Sgc161489 		    "uc_pwr_states = %x", level, pm->uc_pwr_states);
4953341Sgc161489 
4963341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
4973341Sgc161489 
4983341Sgc161489 		return (rval);
4993341Sgc161489 	}
5003341Sgc161489 
5013528Sgc161489 	rval = usba_common_power(dip, &(pm->uc_current_power),
5023528Sgc161489 	    &(usb_ia->ia_dev_state), level);
5033341Sgc161489 
5043341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
5053341Sgc161489 
5063341Sgc161489 	return (rval);
5073341Sgc161489 }
5083341Sgc161489 
5093341Sgc161489 /*
5103341Sgc161489  * attach/resume entry point
5113341Sgc161489  */
5123341Sgc161489 static int
usb_ia_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)5133341Sgc161489 usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5143341Sgc161489 {
5153341Sgc161489 	int		instance = ddi_get_instance(dip);
5163341Sgc161489 	usb_ia_t	*usb_ia = NULL;
5173341Sgc161489 	uint_t		n_ifs;
5183341Sgc161489 	size_t		size;
5193341Sgc161489 
5203341Sgc161489 	switch (cmd) {
5213341Sgc161489 	case DDI_ATTACH:
5223341Sgc161489 
5233341Sgc161489 		break;
5243341Sgc161489 	case DDI_RESUME:
5253341Sgc161489 		usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
5263341Sgc161489 		(void) usb_ia_restore_device_state(dip, usb_ia);
5273341Sgc161489 
5283341Sgc161489 		return (DDI_SUCCESS);
5293341Sgc161489 	default:
5303341Sgc161489 
5313341Sgc161489 		return (DDI_FAILURE);
5323341Sgc161489 	}
5333341Sgc161489 
5343341Sgc161489 	/*
5353341Sgc161489 	 * Attach:
5363341Sgc161489 	 *
5373341Sgc161489 	 * Allocate soft state and initialize
5383341Sgc161489 	 */
5393341Sgc161489 	if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) {
5403341Sgc161489 		goto fail;
5413341Sgc161489 	}
5423341Sgc161489 
5433341Sgc161489 	usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
5443341Sgc161489 	if (usb_ia == NULL) {
5453341Sgc161489 
5463341Sgc161489 		goto fail;
5473341Sgc161489 	}
5483341Sgc161489 
5493341Sgc161489 	/* allocate handle for logging of messages */
5503341Sgc161489 	usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia",
5516898Sfb209375 	    &usb_ia_errlevel,
5526898Sfb209375 	    &usb_ia_errmask, &usb_ia_instance_debug,
5536898Sfb209375 	    0);
5543341Sgc161489 
5553341Sgc161489 	usb_ia->ia_dip	= dip;
5563341Sgc161489 	usb_ia->ia_instance = instance;
5573341Sgc161489 	usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
5583341Sgc161489 	    DDI_PROP_DONTPASS, "interface", -1);
5593341Sgc161489 	usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
5603341Sgc161489 	    DDI_PROP_DONTPASS, "interface-count", -1);
5613341Sgc161489 
5623341Sgc161489 	if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) {
5633341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
5643341Sgc161489 		    "interface-association property failed");
5653341Sgc161489 
5663341Sgc161489 		goto fail;
5673341Sgc161489 	}
5683341Sgc161489 
5693341Sgc161489 	/* attach client driver to USBA */
5703341Sgc161489 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
5713341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
5723341Sgc161489 		    "usb_client_attach failed");
5733341Sgc161489 		goto fail;
5743341Sgc161489 	}
5753341Sgc161489 	if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE,
5763341Sgc161489 	    0) != USB_SUCCESS) {
5773341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
5783341Sgc161489 		    "usb_get_dev_data failed");
5793341Sgc161489 		goto fail;
5803341Sgc161489 	}
5813341Sgc161489 
5823341Sgc161489 	mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER,
5833341Sgc161489 	    usb_ia->ia_dev_data->dev_iblock_cookie);
5843341Sgc161489 
5853341Sgc161489 	usb_free_dev_data(dip, usb_ia->ia_dev_data);
5863341Sgc161489 	usb_ia->ia_dev_data = NULL;
5873341Sgc161489 
5883341Sgc161489 	usb_ia->ia_init_state |= USB_IA_LOCK_INIT;
5893341Sgc161489 
5903341Sgc161489 	if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance,
5913341Sgc161489 	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
5923341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
5933341Sgc161489 		    "cannot create devctl minor node");
5943341Sgc161489 		goto fail;
5953341Sgc161489 	}
5963341Sgc161489 
5973341Sgc161489 	usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED;
5983341Sgc161489 
5993341Sgc161489 	/*
6003341Sgc161489 	 * allocate array for keeping track of child dips
6013341Sgc161489 	 */
6023341Sgc161489 	n_ifs = usb_ia->ia_n_ifs;
6033341Sgc161489 	usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
6043341Sgc161489 
6053341Sgc161489 	usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP);
6063341Sgc161489 	usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
6076898Sfb209375 	    KM_SLEEP);
6083341Sgc161489 	/*
6093341Sgc161489 	 * Event handling: definition and registration
6103341Sgc161489 	 * get event handle for events that we have defined
6113341Sgc161489 	 */
6123341Sgc161489 	(void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl,
6136898Sfb209375 	    NDI_SLEEP);
6143341Sgc161489 
6153341Sgc161489 	/* bind event set to the handle */
6163341Sgc161489 	if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events,
6173341Sgc161489 	    NDI_SLEEP)) {
6183341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
6193341Sgc161489 		    "usb_ia_attach: binding event set failed");
6203341Sgc161489 
6213341Sgc161489 		goto fail;
6223341Sgc161489 	}
6233341Sgc161489 
6243341Sgc161489 	usb_ia->ia_dev_state = USB_DEV_ONLINE;
6253341Sgc161489 
6263341Sgc161489 	/*
6273341Sgc161489 	 * now create components to power manage this device
6283341Sgc161489 	 * before attaching children
6293341Sgc161489 	 */
6303341Sgc161489 	usb_ia_create_pm_components(dip, usb_ia);
6313341Sgc161489 
6323341Sgc161489 	/* event registration for events from our parent */
6333341Sgc161489 	usba_common_register_events(dip, n_ifs, usb_ia_event_cb);
6343341Sgc161489 
6353341Sgc161489 	usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED;
6363341Sgc161489 
6373341Sgc161489 	ddi_report_dev(dip);
6383341Sgc161489 
6393341Sgc161489 	return (DDI_SUCCESS);
6403341Sgc161489 
6413341Sgc161489 fail:
6423341Sgc161489 	USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach",
6433341Sgc161489 	    instance);
6443341Sgc161489 
6453341Sgc161489 	if (usb_ia) {
6463341Sgc161489 		(void) usb_ia_cleanup(usb_ia);
6473341Sgc161489 	}
6483341Sgc161489 
6493341Sgc161489 	return (DDI_FAILURE);
6503341Sgc161489 }
6513341Sgc161489 
6523341Sgc161489 
6533341Sgc161489 /* detach or suspend this instance */
6543341Sgc161489 static int
usb_ia_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)6553341Sgc161489 usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
6563341Sgc161489 {
6573341Sgc161489 	usb_ia_t	*usb_ia = usb_ia_obtain_state(dip);
6583341Sgc161489 
6593341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
6603341Sgc161489 	    "usb_ia_detach: cmd = 0x%x", cmd);
6613341Sgc161489 
6623341Sgc161489 	switch (cmd) {
6633341Sgc161489 	case DDI_DETACH:
6643341Sgc161489 
6653341Sgc161489 		return (usb_ia_cleanup(usb_ia));
6663341Sgc161489 	case DDI_SUSPEND:
6673341Sgc161489 		/* nothing to do */
6683341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
6693341Sgc161489 		usb_ia->ia_dev_state = USB_DEV_SUSPENDED;
6703341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
6713341Sgc161489 
6723341Sgc161489 		return (DDI_SUCCESS);
6733341Sgc161489 	default:
6743341Sgc161489 
6753341Sgc161489 		return (DDI_FAILURE);
6763341Sgc161489 	}
6773341Sgc161489 
6783341Sgc161489 	_NOTE(NOT_REACHED)
6793341Sgc161489 	/* NOTREACHED */
6803341Sgc161489 }
6813341Sgc161489 
6823341Sgc161489 
6833341Sgc161489 /*
6843341Sgc161489  * usb_ia_cleanup:
6853341Sgc161489  *	cleanup usb_ia and deallocate. this function is called for
6863341Sgc161489  *	handling attach failures and detaching including dynamic
6873341Sgc161489  *	reconfiguration
6883341Sgc161489  */
6893341Sgc161489 /*ARGSUSED*/
6903341Sgc161489 static int
usb_ia_cleanup(usb_ia_t * usb_ia)6913341Sgc161489 usb_ia_cleanup(usb_ia_t *usb_ia)
6923341Sgc161489 {
6933341Sgc161489 	usb_common_power_t	*iapm;
6943341Sgc161489 	int			rval;
6953341Sgc161489 	dev_info_t	*dip = usb_ia->ia_dip;
6963341Sgc161489 
6973341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
6983341Sgc161489 	    "usb_ia_cleanup:");
6993341Sgc161489 
7003341Sgc161489 	if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) {
7013341Sgc161489 
7023341Sgc161489 		goto done;
7033341Sgc161489 	}
7043341Sgc161489 
7053341Sgc161489 	/*
7063341Sgc161489 	 * deallocate events, if events are still registered
7073341Sgc161489 	 * (ie. children still attached) then we have to fail the detach
7083341Sgc161489 	 */
7093341Sgc161489 	if (usb_ia->ia_ndi_event_hdl &&
7103341Sgc161489 	    (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) {
7113341Sgc161489 
7123341Sgc161489 		USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
7133341Sgc161489 		    "usb_ia_cleanup: ndi_event_free_hdl failed");
7143341Sgc161489 
7153341Sgc161489 		return (DDI_FAILURE);
7163341Sgc161489 	}
7173341Sgc161489 
7183341Sgc161489 	/*
7193341Sgc161489 	 * Disable the event callbacks, after this point, event
7203341Sgc161489 	 * callbacks will never get called. Note we shouldn't hold
7213341Sgc161489 	 * mutex while unregistering events because there may be a
7223341Sgc161489 	 * competing event callback thread. Event callbacks are done
7233341Sgc161489 	 * with ndi mutex held and this can cause a potential deadlock.
7243341Sgc161489 	 * Note that cleanup can't fail after deregistration of events.
7253341Sgc161489 	 */
7263341Sgc161489 	if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) {
7273341Sgc161489 
7283341Sgc161489 		usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs);
7293341Sgc161489 	}
7303341Sgc161489 
7313341Sgc161489 	iapm = usb_ia->ia_pm;
7323341Sgc161489 
7333341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
7343341Sgc161489 
7353341Sgc161489 	if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) {
7363341Sgc161489 
7373341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
7383341Sgc161489 
7393341Sgc161489 		(void) pm_busy_component(dip, 0);
7403341Sgc161489 		if (iapm->uc_wakeup_enabled) {
7413341Sgc161489 
7423341Sgc161489 			/* First bring the device to full power */
7433341Sgc161489 			(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
7443341Sgc161489 
7453341Sgc161489 			rval = usb_handle_remote_wakeup(dip,
7463341Sgc161489 			    USB_REMOTE_WAKEUP_DISABLE);
7473341Sgc161489 
7483341Sgc161489 			if (rval != DDI_SUCCESS) {
7493341Sgc161489 				USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
7503341Sgc161489 				    usb_ia->ia_log_handle,
7513341Sgc161489 				    "usb_cleanup: disable remote "
7523341Sgc161489 				    "wakeup failed, rval=%d", rval);
7533341Sgc161489 			}
7543341Sgc161489 		}
7553341Sgc161489 
7563341Sgc161489 		(void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF);
7573341Sgc161489 		(void) pm_idle_component(dip, 0);
7583341Sgc161489 	} else {
7593341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
7603341Sgc161489 	}
7613341Sgc161489 
7623341Sgc161489 	if (iapm) {
7633341Sgc161489 		kmem_free(iapm, sizeof (usb_common_power_t));
7643341Sgc161489 	}
7653341Sgc161489 
7663341Sgc161489 	/* free children list */
7673341Sgc161489 	if (usb_ia->ia_children_dips) {
7683341Sgc161489 		kmem_free(usb_ia->ia_children_dips,
7696898Sfb209375 		    usb_ia->ia_cd_list_length);
7703341Sgc161489 	}
7713341Sgc161489 
7723341Sgc161489 	if (usb_ia->ia_child_events) {
7733341Sgc161489 		kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) *
7746898Sfb209375 		    usb_ia->ia_n_ifs);
7753341Sgc161489 	}
7763341Sgc161489 
7773341Sgc161489 	if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) {
7783341Sgc161489 		ddi_remove_minor_node(dip, NULL);
7793341Sgc161489 	}
7803341Sgc161489 
7813341Sgc161489 	mutex_destroy(&usb_ia->ia_mutex);
7823341Sgc161489 
7833341Sgc161489 done:
7843341Sgc161489 	usb_client_detach(dip, usb_ia->ia_dev_data);
7853341Sgc161489 
7863341Sgc161489 	usb_free_log_hdl(usb_ia->ia_log_handle);
7873341Sgc161489 	ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip));
7883341Sgc161489 
7893341Sgc161489 	ddi_prop_remove_all(dip);
7903341Sgc161489 
7913341Sgc161489 	return (DDI_SUCCESS);
7923341Sgc161489 }
7933341Sgc161489 
7943341Sgc161489 /*
7953341Sgc161489  * usb_ia_create_children:
7963341Sgc161489  */
7973341Sgc161489 static void
usb_ia_create_children(usb_ia_t * usb_ia)7983341Sgc161489 usb_ia_create_children(usb_ia_t *usb_ia)
7993341Sgc161489 {
8003341Sgc161489 	usba_device_t		*usba_device;
8013341Sgc161489 	uint_t			n_ifs, first_if;
8023341Sgc161489 	uint_t			i;
8033341Sgc161489 	dev_info_t		*cdip;
8043341Sgc161489 
8053341Sgc161489 	usba_device = usba_get_usba_device(usb_ia->ia_dip);
8063341Sgc161489 
8073341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
8083341Sgc161489 	    "usb_ia_attach_child_drivers: port = %d, address = %d",
8093341Sgc161489 	    usba_device->usb_port, usba_device->usb_addr);
8103341Sgc161489 
8113341Sgc161489 	n_ifs = usb_ia->ia_n_ifs;
8123341Sgc161489 	first_if = usb_ia->ia_first_if;
8133341Sgc161489 
8143341Sgc161489 	/*
8153341Sgc161489 	 * create all children if not already present
8163341Sgc161489 	 */
8173341Sgc161489 	for (i = 0; i < n_ifs; i++) {
8183341Sgc161489 		if (usb_ia->ia_children_dips[i] != NULL) {
8193341Sgc161489 
8203341Sgc161489 			continue;
8213341Sgc161489 		}
8223341Sgc161489 
8233341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
8243341Sgc161489 		cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i);
8253341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
8263341Sgc161489 
8273341Sgc161489 		if (cdip != NULL) {
8283341Sgc161489 			(void) usba_bind_driver(cdip);
8293341Sgc161489 			usb_ia->ia_children_dips[i] = cdip;
8303341Sgc161489 		}
8313341Sgc161489 	}
8323341Sgc161489 
8333341Sgc161489 }
8343341Sgc161489 
8353341Sgc161489 
8363341Sgc161489 /*
8373341Sgc161489  * event support
8383341Sgc161489  */
8393341Sgc161489 static int
usb_ia_busop_get_eventcookie(dev_info_t * dip,dev_info_t * rdip,char * eventname,ddi_eventcookie_t * cookie)8403341Sgc161489 usb_ia_busop_get_eventcookie(dev_info_t *dip,
8413341Sgc161489 	dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
8423341Sgc161489 {
8433341Sgc161489 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
8443341Sgc161489 
8453341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
8463341Sgc161489 	    "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
8473341Sgc161489 	    "event=%s", (void *)dip, (void *)rdip, eventname);
8483341Sgc161489 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
8493341Sgc161489 	    "(dip=%s%d rdip=%s%d)",
8503341Sgc161489 	    ddi_driver_name(dip), ddi_get_instance(dip),
8513341Sgc161489 	    ddi_driver_name(rdip), ddi_get_instance(rdip));
8523341Sgc161489 
8533341Sgc161489 	/* return event cookie, iblock cookie, and level */
8543341Sgc161489 	return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl,
8553341Sgc161489 	    rdip, eventname, cookie, NDI_EVENT_NOPASS));
8563341Sgc161489 }
8573341Sgc161489 
8583341Sgc161489 
8593341Sgc161489 static int
usb_ia_busop_add_eventcall(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void (* callback)(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata),void * arg,ddi_callback_id_t * cb_id)8603341Sgc161489 usb_ia_busop_add_eventcall(dev_info_t *dip,
8613341Sgc161489 	dev_info_t *rdip,
8623341Sgc161489 	ddi_eventcookie_t cookie,
8633341Sgc161489 	void (*callback)(dev_info_t *dip,
8643341Sgc161489 	    ddi_eventcookie_t cookie, void *arg,
8653341Sgc161489 	    void *bus_impldata),
8663341Sgc161489 	void *arg, ddi_callback_id_t *cb_id)
8673341Sgc161489 {
8683341Sgc161489 	int	ifno;
8693341Sgc161489 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
8703341Sgc161489 
8713341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
8723341Sgc161489 	ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if;
8733341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
8743341Sgc161489 
8753341Sgc161489 	if (ifno < 0) {
8763341Sgc161489 		ifno = 0;
8773341Sgc161489 	}
8783341Sgc161489 
8793341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
8803341Sgc161489 	    "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p "
8813341Sgc161489 	    "cookie=0x%p, cb=0x%p, arg=0x%p",
8823341Sgc161489 	    (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
8833341Sgc161489 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
8843341Sgc161489 	    "(dip=%s%d rdip=%s%d event=%s)",
8853341Sgc161489 	    ddi_driver_name(dip), ddi_get_instance(dip),
8863341Sgc161489 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
8873341Sgc161489 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
8883341Sgc161489 
8893341Sgc161489 	/* Set flag on children registering events */
8903341Sgc161489 	switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) {
8913341Sgc161489 	case USBA_EVENT_TAG_HOT_REMOVAL:
8923341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
8933341Sgc161489 		usb_ia->ia_child_events[ifno] |=
8943341Sgc161489 		    USB_IA_CHILD_EVENT_DISCONNECT;
8953341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
8963341Sgc161489 
8973341Sgc161489 		break;
8983341Sgc161489 	case USBA_EVENT_TAG_PRE_SUSPEND:
8993341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
9003341Sgc161489 		usb_ia->ia_child_events[ifno] |=
9013341Sgc161489 		    USB_IA_CHILD_EVENT_PRESUSPEND;
9023341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
9033341Sgc161489 
9043341Sgc161489 		break;
9053341Sgc161489 	default:
9063341Sgc161489 
9073341Sgc161489 		break;
9083341Sgc161489 	}
9093341Sgc161489 	/* add callback (perform registration) */
9103341Sgc161489 	return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl,
9113341Sgc161489 	    rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
9123341Sgc161489 }
9133341Sgc161489 
9143341Sgc161489 
9153341Sgc161489 static int
usb_ia_busop_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)9163341Sgc161489 usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
9173341Sgc161489 {
9183341Sgc161489 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
9193341Sgc161489 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
9203341Sgc161489 
9213341Sgc161489 	ASSERT(cb);
9223341Sgc161489 
9233341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
9243341Sgc161489 	    "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
9256898Sfb209375 	    "cookie=0x%p", (void *)dip, (void *)cb->ndi_evtcb_dip,
9266898Sfb209375 	    (void *)cb->ndi_evtcb_cookie);
9273341Sgc161489 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
9283341Sgc161489 	    "(dip=%s%d rdip=%s%d event=%s)",
9293341Sgc161489 	    ddi_driver_name(dip), ddi_get_instance(dip),
9303341Sgc161489 	    ddi_driver_name(cb->ndi_evtcb_dip),
9313341Sgc161489 	    ddi_get_instance(cb->ndi_evtcb_dip),
9323341Sgc161489 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl,
9333341Sgc161489 	    cb->ndi_evtcb_cookie));
9343341Sgc161489 
9353341Sgc161489 	/* remove event registration from our event set */
9363341Sgc161489 	return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id));
9373341Sgc161489 }
9383341Sgc161489 
9393341Sgc161489 
9403341Sgc161489 static int
usb_ia_busop_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * bus_impldata)9413341Sgc161489 usb_ia_busop_post_event(dev_info_t *dip,
9423341Sgc161489 	dev_info_t *rdip,
9433341Sgc161489 	ddi_eventcookie_t cookie,
9443341Sgc161489 	void *bus_impldata)
9453341Sgc161489 {
9463341Sgc161489 	usb_ia_t  *usb_ia = usb_ia_obtain_state(dip);
9473341Sgc161489 
9483341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
9493341Sgc161489 	    "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p "
9503341Sgc161489 	    "cookie=0x%p, impl=0x%p",
9513341Sgc161489 	    (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
9523341Sgc161489 	USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
9533341Sgc161489 	    "(dip=%s%d rdip=%s%d event=%s)",
9543341Sgc161489 	    ddi_driver_name(dip), ddi_get_instance(dip),
9553341Sgc161489 	    ddi_driver_name(rdip), ddi_get_instance(rdip),
9563341Sgc161489 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
9573341Sgc161489 
9583341Sgc161489 	/* post event to all children registered for this event */
9593341Sgc161489 	return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip,
9603341Sgc161489 	    cookie, bus_impldata));
9613341Sgc161489 }
9623341Sgc161489 
9633341Sgc161489 
9643341Sgc161489 /*
9653341Sgc161489  * usb_ia_restore_device_state
9663341Sgc161489  *	set the original configuration of the device
9673341Sgc161489  */
9683341Sgc161489 static int
usb_ia_restore_device_state(dev_info_t * dip,usb_ia_t * usb_ia)9693341Sgc161489 usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia)
9703341Sgc161489 {
9713341Sgc161489 	usb_common_power_t	*iapm;
9723341Sgc161489 
9733341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
9746898Sfb209375 	    "usb_ia_restore_device_state: usb_ia = %p", (void *)usb_ia);
9753341Sgc161489 
9763341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
9773341Sgc161489 	iapm = usb_ia->ia_pm;
9783341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
9793341Sgc161489 
9803341Sgc161489 	/* First bring the device to full power */
9813341Sgc161489 	(void) pm_busy_component(dip, 0);
9823341Sgc161489 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
9833341Sgc161489 
9843341Sgc161489 	if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0,
9853341Sgc161489 	    DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
9863341Sgc161489 
9873341Sgc161489 		/* change the device state from suspended to disconnected */
9883341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
9893341Sgc161489 		usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
9903341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
9913341Sgc161489 		(void) pm_idle_component(dip, 0);
9923341Sgc161489 
9933341Sgc161489 		return (USB_FAILURE);
9943341Sgc161489 	}
9953341Sgc161489 
9963341Sgc161489 	/*
9973341Sgc161489 	 * if the device had remote wakeup earlier,
9983341Sgc161489 	 * enable it again
9993341Sgc161489 	 */
10003341Sgc161489 	if (iapm->uc_wakeup_enabled) {
10013341Sgc161489 		(void) usb_handle_remote_wakeup(usb_ia->ia_dip,
10023341Sgc161489 		    USB_REMOTE_WAKEUP_ENABLE);
10033341Sgc161489 	}
10043341Sgc161489 
10053341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
10063341Sgc161489 	usb_ia->ia_dev_state = USB_DEV_ONLINE;
10073341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
10083341Sgc161489 
10093341Sgc161489 	(void) pm_idle_component(dip, 0);
10103341Sgc161489 
10113341Sgc161489 	return (USB_SUCCESS);
10123341Sgc161489 }
10133341Sgc161489 
10143341Sgc161489 
10153341Sgc161489 /*
10163341Sgc161489  * usb_ia_event_cb()
10173341Sgc161489  *	handle disconnect and connect events
10183341Sgc161489  */
10193341Sgc161489 static void
usb_ia_event_cb(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata)10203341Sgc161489 usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
10213341Sgc161489 	void *arg, void *bus_impldata)
10223341Sgc161489 {
10233341Sgc161489 	int		i, tag;
10243341Sgc161489 	usb_ia_t	*usb_ia = usb_ia_obtain_state(dip);
10253341Sgc161489 	dev_info_t	*child_dip;
10263341Sgc161489 	ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
10273341Sgc161489 
10283341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
10293341Sgc161489 	    "usb_ia_event_cb: dip=0x%p, cookie=0x%p, "
10303341Sgc161489 	    "arg=0x%p, impl=0x%p",
10313341Sgc161489 	    (void *)dip, (void *)cookie, arg, bus_impldata);
10323341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
10333341Sgc161489 	    "(dip=%s%d event=%s)",
10343341Sgc161489 	    ddi_driver_name(dip), ddi_get_instance(dip),
10353341Sgc161489 	    ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
10363341Sgc161489 
10373341Sgc161489 	tag = NDI_EVENT_TAG(cookie);
10383341Sgc161489 	rm_cookie = ndi_event_tag_to_cookie(
10393341Sgc161489 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
10403341Sgc161489 	suspend_cookie = ndi_event_tag_to_cookie(
10413341Sgc161489 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
10423341Sgc161489 	ins_cookie = ndi_event_tag_to_cookie(
10433341Sgc161489 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
10443341Sgc161489 	resume_cookie = ndi_event_tag_to_cookie(
10453341Sgc161489 	    usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
10463341Sgc161489 
10473341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
10483341Sgc161489 	switch (tag) {
10493341Sgc161489 	case USBA_EVENT_TAG_HOT_REMOVAL:
10503341Sgc161489 		if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) {
10513341Sgc161489 			USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
10523341Sgc161489 			    usb_ia->ia_log_handle,
10533341Sgc161489 			    "usb_ia_event_cb: Device already disconnected");
10543341Sgc161489 		} else {
10553341Sgc161489 			/* we are disconnected so set our state now */
10563341Sgc161489 			usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
10573341Sgc161489 			for (i = 0; i < usb_ia->ia_n_ifs; i++) {
10583341Sgc161489 				usb_ia->ia_child_events[i] &= ~
10593341Sgc161489 				    USB_IA_CHILD_EVENT_DISCONNECT;
10603341Sgc161489 			}
10613341Sgc161489 			mutex_exit(&usb_ia->ia_mutex);
10623341Sgc161489 
10633341Sgc161489 			/* pass disconnect event to all the children */
10643341Sgc161489 			(void) ndi_event_run_callbacks(
10653341Sgc161489 			    usb_ia->ia_ndi_event_hdl, NULL,
10663341Sgc161489 			    rm_cookie, bus_impldata);
10673341Sgc161489 
10683341Sgc161489 			mutex_enter(&usb_ia->ia_mutex);
10693341Sgc161489 		}
10703341Sgc161489 		break;
10713341Sgc161489 	case USBA_EVENT_TAG_PRE_SUSPEND:
10723341Sgc161489 		/* set our state *after* suspending children */
10733341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
10743341Sgc161489 
10753341Sgc161489 		/* pass pre_suspend event to all the children */
10763341Sgc161489 		(void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
10773341Sgc161489 		    NULL, suspend_cookie, bus_impldata);
10783341Sgc161489 
10793341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
10803341Sgc161489 		for (i = 0; i < usb_ia->ia_n_ifs; i++) {
10813341Sgc161489 			usb_ia->ia_child_events[i] &= ~
10823341Sgc161489 			    USB_IA_CHILD_EVENT_PRESUSPEND;
10833341Sgc161489 		}
10843341Sgc161489 		break;
10853341Sgc161489 	case USBA_EVENT_TAG_HOT_INSERTION:
10863341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
10873341Sgc161489 		if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) {
10883341Sgc161489 
10893341Sgc161489 			/*
10903341Sgc161489 			 * Check to see if this child has missed the disconnect
10913341Sgc161489 			 * event before it registered for event cb
10923341Sgc161489 			 */
10933341Sgc161489 			mutex_enter(&usb_ia->ia_mutex);
10943341Sgc161489 			for (i = 0; i < usb_ia->ia_n_ifs; i++) {
10953341Sgc161489 				if (usb_ia->ia_child_events[i] &
10963341Sgc161489 				    USB_IA_CHILD_EVENT_DISCONNECT) {
10973341Sgc161489 					usb_ia->ia_child_events[i] &=
10983341Sgc161489 					    ~USB_IA_CHILD_EVENT_DISCONNECT;
10993341Sgc161489 					child_dip =
11003341Sgc161489 					    usb_ia->ia_children_dips[i];
11013341Sgc161489 					mutex_exit(&usb_ia->ia_mutex);
11023341Sgc161489 
11033341Sgc161489 					/* post the missed disconnect */
11043341Sgc161489 					(void) ndi_event_do_callback(
11053341Sgc161489 					    usb_ia->ia_ndi_event_hdl,
11063341Sgc161489 					    child_dip,
11073341Sgc161489 					    rm_cookie,
11083341Sgc161489 					    bus_impldata);
11093341Sgc161489 					mutex_enter(&usb_ia->ia_mutex);
11103341Sgc161489 				}
11113341Sgc161489 			}
11123341Sgc161489 			mutex_exit(&usb_ia->ia_mutex);
11133341Sgc161489 
11143341Sgc161489 			/* pass reconnect event to all the children */
11153341Sgc161489 			(void) ndi_event_run_callbacks(
11163341Sgc161489 			    usb_ia->ia_ndi_event_hdl, NULL,
11173341Sgc161489 			    ins_cookie, bus_impldata);
11183341Sgc161489 
11193341Sgc161489 		}
11203341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
11213341Sgc161489 		break;
11223341Sgc161489 	case USBA_EVENT_TAG_POST_RESUME:
11233341Sgc161489 		/*
11243341Sgc161489 		 * Check to see if this child has missed the pre-suspend
11253341Sgc161489 		 * event before it registered for event cb
11263341Sgc161489 		 */
11273341Sgc161489 		for (i = 0; i < usb_ia->ia_n_ifs; i++) {
11283341Sgc161489 			if (usb_ia->ia_child_events[i] &
11293341Sgc161489 			    USB_IA_CHILD_EVENT_PRESUSPEND) {
11303341Sgc161489 				usb_ia->ia_child_events[i] &=
11313341Sgc161489 				    ~USB_IA_CHILD_EVENT_PRESUSPEND;
11323341Sgc161489 				child_dip = usb_ia->ia_children_dips[i];
11333341Sgc161489 				mutex_exit(&usb_ia->ia_mutex);
11343341Sgc161489 
11353341Sgc161489 				/* post the missed pre-suspend event */
11363341Sgc161489 				(void) ndi_event_do_callback(
11373341Sgc161489 				    usb_ia->ia_ndi_event_hdl,
11383341Sgc161489 				    child_dip, suspend_cookie,
11393341Sgc161489 				    bus_impldata);
11403341Sgc161489 				mutex_enter(&usb_ia->ia_mutex);
11413341Sgc161489 			}
11423341Sgc161489 		}
11433341Sgc161489 		mutex_exit(&usb_ia->ia_mutex);
11443341Sgc161489 
11453341Sgc161489 		/* pass post_resume event to all the children */
11463341Sgc161489 		(void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
11473341Sgc161489 		    NULL, resume_cookie, bus_impldata);
11483341Sgc161489 
11493341Sgc161489 		mutex_enter(&usb_ia->ia_mutex);
11503341Sgc161489 		break;
11513341Sgc161489 	}
11523341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
11533341Sgc161489 
11543341Sgc161489 }
11553341Sgc161489 
11563341Sgc161489 /*
11573341Sgc161489  * create the pm components required for power management
11583341Sgc161489  */
11593341Sgc161489 static void
usb_ia_create_pm_components(dev_info_t * dip,usb_ia_t * usb_ia)11603341Sgc161489 usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia)
11613341Sgc161489 {
11623341Sgc161489 	usb_common_power_t	*iapm;
11633341Sgc161489 	uint_t			pwr_states;
11643341Sgc161489 
11653341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
11663341Sgc161489 	    "usb_ia_create_pm_components: Begin");
11673341Sgc161489 
11683341Sgc161489 	/* Allocate the PM state structure */
11693341Sgc161489 	iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
11703341Sgc161489 
11713341Sgc161489 	mutex_enter(&usb_ia->ia_mutex);
11723341Sgc161489 	usb_ia->ia_pm = iapm;
11733341Sgc161489 	iapm->uc_usb_statep = usb_ia;
11743341Sgc161489 	iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
11753341Sgc161489 	iapm->uc_current_power = USB_DEV_OS_FULL_PWR;
11763341Sgc161489 	mutex_exit(&usb_ia->ia_mutex);
11773341Sgc161489 
11783341Sgc161489 	/*
11793341Sgc161489 	 * By not enabling parental notification, PM enforces
11803341Sgc161489 	 * "strict parental dependency" meaning, usb_ia won't
11813341Sgc161489 	 * power off until any of its children are in full power.
11823341Sgc161489 	 */
11833341Sgc161489 
11843341Sgc161489 	/*
11853341Sgc161489 	 * there are 3 scenarios:
11863341Sgc161489 	 * 1. a well behaved device should have remote wakeup
11873341Sgc161489 	 * at interface and device level. If the interface
11883341Sgc161489 	 * wakes up, usb_ia will wake up
11893341Sgc161489 	 * 2. if the device doesn't have remote wake up and
11903341Sgc161489 	 * the interface has, PM will still work, ie.
11913341Sgc161489 	 * the interfaces wakes up and usb_ia wakes up
11923341Sgc161489 	 * 3. if neither the interface nor device has remote
11933341Sgc161489 	 * wakeup, the interface will wake up when it is opened
11943341Sgc161489 	 * and goes to sleep after being closed for a while
11953341Sgc161489 	 * In this case usb_ia should also go to sleep shortly
11963341Sgc161489 	 * thereafter
11973341Sgc161489 	 * In all scenarios it doesn't really matter whether
11983341Sgc161489 	 * remote wakeup at the device level is enabled or not
11993341Sgc161489 	 * but we do it anyways
12003341Sgc161489 	 */
12013341Sgc161489 	if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
12023341Sgc161489 	    USB_SUCCESS) {
12033341Sgc161489 		USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle,
12043341Sgc161489 		    "usb_ia_create_pm_components: "
12053341Sgc161489 		    "Remote Wakeup Enabled");
12063341Sgc161489 		iapm->uc_wakeup_enabled = 1;
12073341Sgc161489 	}
12083341Sgc161489 
12093341Sgc161489 	if (usb_create_pm_components(dip, &pwr_states) ==
12103341Sgc161489 	    USB_SUCCESS) {
12113341Sgc161489 		iapm->uc_pwr_states = (uint8_t)pwr_states;
12123341Sgc161489 		(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
12133341Sgc161489 	}
12143341Sgc161489 
12153341Sgc161489 	USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
12163341Sgc161489 	    "usb_ia_create_pm_components: End");
12173341Sgc161489 }
12183341Sgc161489 
12193341Sgc161489 
12203341Sgc161489 /*
12213341Sgc161489  * usb_ia_obtain_state:
12223341Sgc161489  */
12233341Sgc161489 static usb_ia_t *
usb_ia_obtain_state(dev_info_t * dip)12243341Sgc161489 usb_ia_obtain_state(dev_info_t *dip)
12253341Sgc161489 {
12263341Sgc161489 	int instance = ddi_get_instance(dip);
12273341Sgc161489 	usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance);
12283341Sgc161489 
12293341Sgc161489 	ASSERT(statep != NULL);
12303341Sgc161489 
12313341Sgc161489 	return (statep);
12323341Sgc161489 }
1233