summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgc161489 <none@none>2006-12-27 22:00:25 -0800
committergc161489 <none@none>2006-12-27 22:00:25 -0800
commitd73ae94e59c019f5cc3221ee0a0012d02091b40e (patch)
tree193b1ba4909675d6fe1bb07678ab5a9970a230c3
parentb051ecf6ce2f5fb47d73df411b0b95fa2b53ab9f (diff)
downloadillumos-joyent-d73ae94e59c019f5cc3221ee0a0012d02091b40e.tar.gz
PSARC 2006/649 USB Interface Association support
6463853 USB IAD should be supported in solaris (updated usb bindings, FWARC 2006/671)
-rw-r--r--usr/src/pkgdefs/SUNWusb/postinstall7
-rw-r--r--usr/src/pkgdefs/SUNWusb/preremove12
-rw-r--r--usr/src/pkgdefs/SUNWusb/prototype_i3869
-rw-r--r--usr/src/pkgdefs/SUNWusb/prototype_sparc8
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/io/usb/inc.flg2
-rw-r--r--usr/src/uts/common/io/usb/usb_ia/usb_ia.c1230
-rw-r--r--usr/src/uts/common/io/usb/usb_mid/usb_mid.c400
-rw-r--r--usr/src/uts/common/io/usb/usba/hcdi.c10
-rw-r--r--usr/src/uts/common/io/usb/usba/parser.c40
-rw-r--r--usr/src/uts/common/io/usb/usba/usba.c314
-rw-r--r--usr/src/uts/common/io/usb/usba/usbai_util.c267
-rw-r--r--usr/src/uts/common/io/warlock/usb_ia.wlcmd32
-rw-r--r--usr/src/uts/common/io/warlock/usb_ia_with_usba.wlcmd172
-rw-r--r--usr/src/uts/common/sys/usb/usb_ia/usb_iavar.h114
-rw-r--r--usr/src/uts/common/sys/usb/usb_mid/usb_midvar.h43
-rw-r--r--usr/src/uts/common/sys/usb/usba/usba_impl.h9
-rw-r--r--usr/src/uts/common/sys/usb/usba/usba_private.h65
-rw-r--r--usr/src/uts/common/sys/usb/usbai.h33
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared1
-rw-r--r--usr/src/uts/intel/usb_ia/Makefile149
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared2
-rw-r--r--usr/src/uts/sparc/usb_ia/Makefile148
-rw-r--r--usr/src/uts/sparc/warlock/Makefile1
25 files changed, 2691 insertions, 386 deletions
diff --git a/usr/src/pkgdefs/SUNWusb/postinstall b/usr/src/pkgdefs/SUNWusb/postinstall
index bb0211c804..4f865c3169 100644
--- a/usr/src/pkgdefs/SUNWusb/postinstall
+++ b/usr/src/pkgdefs/SUNWusb/postinstall
@@ -39,9 +39,9 @@ LINKDIR=${BASEDIR}/dev/usb
LINKFILES="hub* mass-storage* device*"
# since ohci, uhci and ehci are self probing nexus drivers,
-# add_drv -n hid, hubd and usb_mid before add_drv ohci/uhci/ehci.
+# add_drv -n hid, hubd, usb_ia and usb_mid before add_drv ohci/uhci/ehci.
# ohci/uhci/ehci will create the hub and usb,device nodes and attach
-# hubd and usb_mid drivers
+# hubd, usb_mid and usb_ia drivers
not_installed() {
driver=$1
@@ -61,6 +61,9 @@ not_installed hubd || add_drv ${BASEDIR_OPT} -m '* 0644 root sys' \
not_installed scsa2usb || add_drv ${BASEDIR_OPT} \
-i '"usbif,class8" "usb584,222"' -n scsa2usb || EXIT=1
+not_installed usb_ia || add_drv ${BASEDIR_OPT} -i '"usb,ia"' -n usb_ia ||
+EXIT=1
+
not_installed usb_mid || add_drv ${BASEDIR_OPT} -i '"usb,device"' -n usb_mid ||
EXIT=1
diff --git a/usr/src/pkgdefs/SUNWusb/preremove b/usr/src/pkgdefs/SUNWusb/preremove
index abd0183b04..1a9d27dc07 100644
--- a/usr/src/pkgdefs/SUNWusb/preremove
+++ b/usr/src/pkgdefs/SUNWusb/preremove
@@ -3,9 +3,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -49,6 +48,11 @@ then
rem_drv -b ${BASEDIR} hubd || EXIT=1
fi
+if installed usb_ia
+then
+ rem_drv -b ${BASEDIR} usb_ia || EXIT=1
+fi
+
if installed usb_mid
then
rem_drv -b ${BASEDIR} usb_mid || EXIT=1
diff --git a/usr/src/pkgdefs/SUNWusb/prototype_i386 b/usr/src/pkgdefs/SUNWusb/prototype_i386
index 03013c2703..da2bdab5e6 100644
--- a/usr/src/pkgdefs/SUNWusb/prototype_i386
+++ b/usr/src/pkgdefs/SUNWusb/prototype_i386
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -57,6 +56,7 @@ f none kernel/drv/ehci 0755 root sys
f none kernel/drv/hubd 0755 root sys
f none kernel/drv/hid 0755 root sys
f none kernel/drv/usb_mid 0755 root sys
+f none kernel/drv/usb_ia 0755 root sys
f none kernel/drv/scsa2usb 0755 root sys
f none kernel/drv/usbprn 0755 root sys
f none kernel/drv/usb_ac 0755 root sys
@@ -76,6 +76,7 @@ f none kernel/drv/amd64/ehci 0755 root sys
f none kernel/drv/amd64/hubd 0755 root sys
f none kernel/drv/amd64/hid 0755 root sys
f none kernel/drv/amd64/usb_mid 0755 root sys
+f none kernel/drv/amd64/usb_ia 0755 root sys
f none kernel/drv/amd64/scsa2usb 0755 root sys
f none kernel/drv/amd64/usbprn 0755 root sys
f none kernel/drv/amd64/usb_ac 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWusb/prototype_sparc b/usr/src/pkgdefs/SUNWusb/prototype_sparc
index fbadb1329b..4645033258 100644
--- a/usr/src/pkgdefs/SUNWusb/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWusb/prototype_sparc
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -59,6 +58,7 @@ f none kernel/drv/sparcv9/uhci 0755 root sys
f none kernel/drv/sparcv9/hubd 0755 root sys
f none kernel/drv/sparcv9/hid 0755 root sys
f none kernel/drv/sparcv9/usb_mid 0755 root sys
+f none kernel/drv/sparcv9/usb_ia 0755 root sys
f none kernel/drv/sparcv9/scsa2usb 0755 root sys
f none kernel/drv/sparcv9/usbprn 0755 root sys
f none kernel/drv/sparcv9/usb_ac 0755 root sys
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 0f757837ff..413ad69d02 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1260,6 +1260,8 @@ HUBD_OBJS += hubd.o
USB_MID_OBJS += usb_mid.o
+USB_IA_OBJS += usb_ia.o
+
SCSA2USB_OBJS += scsa2usb.o usb_ms_bulkonly.o usb_ms_cbi.o
PHX_OBJS += phx.o
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 120d63aea4..b256e5bb82 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -739,6 +739,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/usb/usb_mid/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/usb/usb_ia/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/usb/usba/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1431,6 +1435,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/usb/scsa2usb/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/usb/usb_mid/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/usb/usb_ia/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/usb/usba/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/io/usb/inc.flg b/usr/src/uts/common/io/usb/inc.flg
index 95b00e986c..516db45458 100644
--- a/usr/src/uts/common/io/usb/inc.flg
+++ b/usr/src/uts/common/io/usb/inc.flg
@@ -64,6 +64,7 @@ find_files "s.*" \
usr/src/uts/sparc/hubd \
usr/src/uts/sparc/scsa2usb \
usr/src/uts/sparc/usb_mid \
+ usr/src/uts/sparc/usb_ia \
usr/src/uts/sparc/usbkbm \
usr/src/uts/sparc/usbms \
usr/src/uts/sparc/usbprn \
@@ -85,6 +86,7 @@ find_files "s.*" \
usr/src/uts/intel/ehci \
usr/src/uts/intel/hubd \
usr/src/uts/intel/usb_mid \
+ usr/src/uts/intel/usb_ia \
usr/src/uts/intel/usba \
usr/src/uts/intel/usbkbm \
usr/src/uts/intel/usbms \
diff --git a/usr/src/uts/common/io/usb/usb_ia/usb_ia.c b/usr/src/uts/common/io/usb/usb_ia/usb_ia.c
new file mode 100644
index 0000000000..fcc534096d
--- /dev/null
+++ b/usr/src/uts/common/io/usb/usb_ia/usb_ia.c
@@ -0,0 +1,1230 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * usb interface association driver
+ *
+ * this driver attempts to the interface association node and
+ * creates/manages child nodes for the included interfaces.
+ */
+
+#if defined(lint) && !defined(DEBUG)
+#define DEBUG 1
+#endif
+#include <sys/usb/usba/usbai_version.h>
+#include <sys/usb/usba.h>
+#include <sys/usb/usba/usba_types.h>
+#include <sys/usb/usba/usba_impl.h>
+#include <sys/usb/usb_ia/usb_iavar.h>
+
+/* Debugging support */
+uint_t usb_ia_errlevel = USB_LOG_L4;
+uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL;
+uint_t usb_ia_instance_debug = (uint_t)-1;
+uint_t usb_ia_bus_config_debug = 0;
+
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug))
+
+_NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
+_NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
+_NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
+
+static struct cb_ops usb_ia_cb_ops = {
+ nodev, /* open */
+ nodev, /* close */
+ nodev, /* strategy */
+ nodev, /* print */
+ nodev, /* dump */
+ nodev, /* read */
+ nodev, /* write */
+ nodev, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ nochpoll, /* poll */
+ ddi_prop_op, /* prop_op */
+ NULL, /* aread */
+ D_MP
+};
+
+static int usb_ia_busop_get_eventcookie(dev_info_t *dip,
+ dev_info_t *rdip,
+ char *eventname,
+ ddi_eventcookie_t *cookie);
+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);
+static int usb_ia_busop_remove_eventcall(dev_info_t *dip,
+ ddi_callback_id_t cb_id);
+static int usb_ia_busop_post_event(dev_info_t *dip,
+ dev_info_t *rdip,
+ ddi_eventcookie_t cookie,
+ void *bus_impldata);
+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);
+static int usb_ia_bus_unconfig(dev_info_t *dip,
+ uint_t flag,
+ ddi_bus_config_op_t op,
+ void *arg);
+
+/*
+ * autoconfiguration data and routines.
+ */
+static int usb_ia_info(dev_info_t *, ddi_info_cmd_t,
+ void *, void **);
+static int usb_ia_attach(dev_info_t *, ddi_attach_cmd_t);
+static int usb_ia_detach(dev_info_t *, ddi_detach_cmd_t);
+
+/* other routines */
+static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *);
+static int usb_ia_bus_ctl(dev_info_t *, dev_info_t *,
+ ddi_ctl_enum_t, void *, void *);
+static int usb_ia_power(dev_info_t *, int, int);
+static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *);
+static usb_ia_t *usb_ia_obtain_state(dev_info_t *);
+static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
+
+/* prototypes */
+static void usb_ia_create_children(usb_ia_t *);
+static int usb_ia_cleanup(usb_ia_t *);
+
+/*
+ * Busops vector
+ */
+static struct bus_ops usb_ia_busops = {
+ BUSO_REV,
+ nullbusmap, /* bus_map */
+ NULL, /* bus_get_intrspec */
+ NULL, /* bus_add_intrspec */
+ NULL, /* bus_remove_intrspec */
+ NULL, /* XXXX bus_map_fault */
+ ddi_dma_map, /* bus_dma_map */
+ ddi_dma_allochdl,
+ ddi_dma_freehdl,
+ ddi_dma_bindhdl,
+ ddi_dma_unbindhdl,
+ ddi_dma_flush,
+ ddi_dma_win,
+ ddi_dma_mctl, /* bus_dma_ctl */
+ usb_ia_bus_ctl, /* bus_ctl */
+ ddi_bus_prop_op, /* bus_prop_op */
+ usb_ia_busop_get_eventcookie,
+ usb_ia_busop_add_eventcall,
+ usb_ia_busop_remove_eventcall,
+ usb_ia_busop_post_event, /* bus_post_event */
+ NULL, /* bus_intr_ctl */
+ usb_ia_bus_config, /* bus_config */
+ usb_ia_bus_unconfig, /* bus_unconfig */
+ NULL, /* bus_fm_init */
+ NULL, /* bus_fm_fini */
+ NULL, /* bus_fm_access_enter */
+ NULL, /* bus_fm_access_exit */
+ NULL /* bus_power */
+};
+
+
+static struct dev_ops usb_ia_ops = {
+ DEVO_REV, /* devo_rev, */
+ 0, /* refcnt */
+ usb_ia_info, /* info */
+ nulldev, /* identify */
+ nulldev, /* probe */
+ usb_ia_attach, /* attach */
+ usb_ia_detach, /* detach */
+ nodev, /* reset */
+ &usb_ia_cb_ops, /* driver operations */
+ &usb_ia_busops, /* bus operations */
+ usb_ia_power /* power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* Type of module. This one is a driver */
+ "USB Interface Association Driver %I%", /* Name of the module. */
+ &usb_ia_ops, /* driver ops */
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, (void *)&modldrv, NULL
+};
+
+#define USB_IA_INITIAL_SOFT_SPACE 4
+static void *usb_ia_statep;
+
+/*
+ * event definition
+ */
+static ndi_event_definition_t usb_ia_ndi_event_defs[] = {
+ {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
+ NDI_EVENT_POST_TO_ALL},
+ {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
+ NDI_EVENT_POST_TO_ALL},
+ {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
+ NDI_EVENT_POST_TO_ALL},
+ {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
+ NDI_EVENT_POST_TO_ALL}
+};
+
+#define USB_IA_N_NDI_EVENTS \
+ (sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t))
+
+static ndi_event_set_t usb_ia_ndi_events = {
+ NDI_EVENTS_REV1, USB_IA_N_NDI_EVENTS, usb_ia_ndi_event_defs};
+
+
+/*
+ * standard driver entry points
+ */
+int
+_init(void)
+{
+ int rval;
+
+ rval = ddi_soft_state_init(&usb_ia_statep, sizeof (struct usb_ia),
+ USB_IA_INITIAL_SOFT_SPACE);
+ if (rval != 0) {
+ return (rval);
+ }
+
+ if ((rval = mod_install(&modlinkage)) != 0) {
+ ddi_soft_state_fini(&usb_ia_statep);
+ return (rval);
+ }
+
+ return (rval);
+}
+
+
+int
+_fini(void)
+{
+ int rval;
+
+ rval = mod_remove(&modlinkage);
+
+ if (rval) {
+ return (rval);
+ }
+
+ ddi_soft_state_fini(&usb_ia_statep);
+
+ return (rval);
+}
+
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+
+/*ARGSUSED*/
+static int
+usb_ia_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+{
+ usb_ia_t *usb_ia;
+ int instance = getminor((dev_t)arg);
+ int error = DDI_FAILURE;
+
+ switch (infocmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ if ((usb_ia = ddi_get_soft_state(usb_ia_statep,
+ instance)) != NULL) {
+ *result = (void *)usb_ia->ia_dip;
+ if (*result != NULL) {
+ error = DDI_SUCCESS;
+ }
+ } else {
+ *result = NULL;
+ }
+ break;
+
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)(intptr_t)instance;
+ error = DDI_SUCCESS;
+ break;
+ default:
+ break;
+ }
+
+ return (error);
+}
+
+
+/*
+ * child post attach/detach notification
+ */
+static void
+usb_ia_post_attach(usb_ia_t *usb_ia, uint8_t ifno, struct attachspec *as)
+{
+ USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_post_attach: ifno = %d result = %d", ifno, as->result);
+
+}
+
+
+static void
+usb_ia_post_detach(usb_ia_t *usb_ia, uint8_t ifno, struct detachspec *ds)
+{
+ USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_post_detach: ifno = %d result = %d", ifno, ds->result);
+
+}
+
+
+/*
+ * bus ctl support. we handle notifications here and the
+ * rest goes up to root hub/hcd
+ */
+/*ARGSUSED*/
+static int
+usb_ia_bus_ctl(dev_info_t *dip,
+ dev_info_t *rdip,
+ ddi_ctl_enum_t op,
+ void *arg,
+ void *result)
+{
+ usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
+ dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
+ usb_ia_t *usb_ia;
+ struct attachspec *as;
+ struct detachspec *ds;
+
+ usb_ia = usb_ia_obtain_state(dip);
+
+ USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_bus_ctl:\n\t"
+ "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
+ dip, rdip, op, arg);
+
+ switch (op) {
+ case DDI_CTLOPS_ATTACH:
+ as = (struct attachspec *)arg;
+
+ switch (as->when) {
+ case DDI_PRE :
+ /* nothing to do basically */
+ USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "DDI_PRE DDI_CTLOPS_ATTACH");
+ break;
+ case DDI_POST :
+ usb_ia_post_attach(usb_ia, usba_get_ifno(rdip),
+ (struct attachspec *)arg);
+ break;
+ }
+
+ break;
+ case DDI_CTLOPS_DETACH:
+ ds = (struct detachspec *)arg;
+
+ switch (ds->when) {
+ case DDI_PRE :
+ /* nothing to do basically */
+ USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "DDI_PRE DDI_CTLOPS_DETACH");
+ break;
+ case DDI_POST :
+ usb_ia_post_detach(usb_ia, usba_get_ifno(rdip),
+ (struct detachspec *)arg);
+ break;
+ }
+
+ break;
+ default:
+ /* pass to root hub to handle */
+ return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
+ }
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * bus enumeration entry points
+ */
+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)
+{
+ int rval, circ;
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+
+ USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
+ "usb_ia_bus_config: op=%d", op);
+
+ if (usb_ia_bus_config_debug) {
+ flag |= NDI_DEVI_DEBUG;
+ }
+
+ ndi_devi_enter(dip, &circ);
+
+ /* enumerate each interface below us */
+ mutex_enter(&usb_ia->ia_mutex);
+ usb_ia_create_children(usb_ia);
+ mutex_exit(&usb_ia->ia_mutex);
+
+ rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
+ ndi_devi_exit(dip, circ);
+
+ return (rval);
+}
+
+
+static int
+usb_ia_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
+ void *arg)
+{
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+
+ dev_info_t *cdip, *mdip;
+ int interface, circular_count;
+ int rval = NDI_SUCCESS;
+
+ USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
+ "usb_ia_bus_unconfig: op=%d", op);
+
+ if (usb_ia_bus_config_debug) {
+ flag |= NDI_DEVI_DEBUG;
+ }
+
+ /*
+ * first offline and if offlining successful, then
+ * remove children
+ */
+ if (op == BUS_UNCONFIG_ALL) {
+ flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
+ }
+
+ ndi_devi_enter(dip, &circular_count);
+ rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
+
+ if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
+ (flag & NDI_AUTODETACH) == 0) {
+ flag |= NDI_DEVI_REMOVE;
+ rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
+ }
+
+ /* update children's list */
+ mutex_enter(&usb_ia->ia_mutex);
+ for (interface = 0; usb_ia->ia_children_dips &&
+ (interface < usb_ia->ia_n_ifs); interface++) {
+ mdip = usb_ia->ia_children_dips[interface];
+
+ /* now search if this dip still exists */
+ for (cdip = ddi_get_child(dip); cdip && (cdip != mdip);
+ cdip = ddi_get_next_sibling(cdip));
+
+ if (cdip != mdip) {
+ /* we lost the dip on this interface */
+ usb_ia->ia_children_dips[interface] = NULL;
+ } else if (cdip) {
+ /*
+ * keep in DS_INITALIZED to prevent parent
+ * from detaching
+ */
+ (void) ddi_initchild(ddi_get_parent(cdip), cdip);
+ }
+ }
+ mutex_exit(&usb_ia->ia_mutex);
+
+ ndi_devi_exit(dip, circular_count);
+
+ USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
+ "usb_ia_bus_config: rval=%d", rval);
+
+ return (rval);
+}
+
+
+/* power entry point */
+/* ARGSUSED */
+static int
+usb_ia_power(dev_info_t *dip, int comp, int level)
+{
+ usb_ia_t *usb_ia;
+ usb_common_power_t *pm;
+ int rval = DDI_FAILURE;
+
+ usb_ia = usb_ia_obtain_state(dip);
+
+ USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_power: Begin: usb_ia = %p, level = %d", usb_ia, level);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ pm = usb_ia->ia_pm;
+
+ /* check if we are transitioning to a legal power level */
+ if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) {
+ USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_power: illegal power level = %d "
+ "uc_pwr_states = %x", level, pm->uc_pwr_states);
+
+ mutex_exit(&usb_ia->ia_mutex);
+
+ return (rval);
+ }
+
+ rval = usba_common_power(dip, pm, &(usb_ia->ia_dev_state), level);
+
+ mutex_exit(&usb_ia->ia_mutex);
+
+ return (rval);
+}
+
+/*
+ * attach/resume entry point
+ */
+static int
+usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int instance = ddi_get_instance(dip);
+ usb_ia_t *usb_ia = NULL;
+ uint_t n_ifs;
+ size_t size;
+
+ switch (cmd) {
+ case DDI_ATTACH:
+
+ break;
+ case DDI_RESUME:
+ usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
+ (void) usb_ia_restore_device_state(dip, usb_ia);
+
+ return (DDI_SUCCESS);
+ default:
+
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Attach:
+ *
+ * Allocate soft state and initialize
+ */
+ if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) {
+ goto fail;
+ }
+
+ usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
+ if (usb_ia == NULL) {
+
+ goto fail;
+ }
+
+ /* allocate handle for logging of messages */
+ usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia",
+ &usb_ia_errlevel,
+ &usb_ia_errmask, &usb_ia_instance_debug,
+ 0);
+
+ usb_ia->ia_dip = dip;
+ usb_ia->ia_instance = instance;
+ usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "interface", -1);
+ usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "interface-count", -1);
+
+ if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) {
+ USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "interface-association property failed");
+
+ goto fail;
+ }
+
+ /* attach client driver to USBA */
+ if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
+ USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "usb_client_attach failed");
+ goto fail;
+ }
+ if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE,
+ 0) != USB_SUCCESS) {
+ USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "usb_get_dev_data failed");
+ goto fail;
+ }
+
+ mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER,
+ usb_ia->ia_dev_data->dev_iblock_cookie);
+
+ usb_free_dev_data(dip, usb_ia->ia_dev_data);
+ usb_ia->ia_dev_data = NULL;
+
+ usb_ia->ia_init_state |= USB_IA_LOCK_INIT;
+
+ if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance,
+ DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
+ USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "cannot create devctl minor node");
+ goto fail;
+ }
+
+ usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED;
+
+ /*
+ * allocate array for keeping track of child dips
+ */
+ n_ifs = usb_ia->ia_n_ifs;
+ usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
+
+ usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP);
+ usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
+ KM_SLEEP);
+ /*
+ * Event handling: definition and registration
+ * get event handle for events that we have defined
+ */
+ (void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl,
+ NDI_SLEEP);
+
+ /* bind event set to the handle */
+ if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events,
+ NDI_SLEEP)) {
+ USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "usb_ia_attach: binding event set failed");
+
+ goto fail;
+ }
+
+ usb_ia->ia_dev_state = USB_DEV_ONLINE;
+
+ /*
+ * now create components to power manage this device
+ * before attaching children
+ */
+ usb_ia_create_pm_components(dip, usb_ia);
+
+ /* event registration for events from our parent */
+ usba_common_register_events(dip, n_ifs, usb_ia_event_cb);
+
+ usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED;
+
+ ddi_report_dev(dip);
+
+ return (DDI_SUCCESS);
+
+fail:
+ USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach",
+ instance);
+
+ if (usb_ia) {
+ (void) usb_ia_cleanup(usb_ia);
+ }
+
+ return (DDI_FAILURE);
+}
+
+
+/* detach or suspend this instance */
+static int
+usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+
+ USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "usb_ia_detach: cmd = 0x%x", cmd);
+
+ switch (cmd) {
+ case DDI_DETACH:
+
+ return (usb_ia_cleanup(usb_ia));
+ case DDI_SUSPEND:
+ /* nothing to do */
+ mutex_enter(&usb_ia->ia_mutex);
+ usb_ia->ia_dev_state = USB_DEV_SUSPENDED;
+ mutex_exit(&usb_ia->ia_mutex);
+
+ return (DDI_SUCCESS);
+ default:
+
+ return (DDI_FAILURE);
+ }
+
+ _NOTE(NOT_REACHED)
+ /* NOTREACHED */
+}
+
+
+/*
+ * usb_ia_cleanup:
+ * cleanup usb_ia and deallocate. this function is called for
+ * handling attach failures and detaching including dynamic
+ * reconfiguration
+ */
+/*ARGSUSED*/
+static int
+usb_ia_cleanup(usb_ia_t *usb_ia)
+{
+ usb_common_power_t *iapm;
+ int rval;
+ dev_info_t *dip = usb_ia->ia_dip;
+
+ USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "usb_ia_cleanup:");
+
+ if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) {
+
+ goto done;
+ }
+
+ /*
+ * deallocate events, if events are still registered
+ * (ie. children still attached) then we have to fail the detach
+ */
+ if (usb_ia->ia_ndi_event_hdl &&
+ (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) {
+
+ USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "usb_ia_cleanup: ndi_event_free_hdl failed");
+
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Disable the event callbacks, after this point, event
+ * callbacks will never get called. Note we shouldn't hold
+ * mutex while unregistering events because there may be a
+ * competing event callback thread. Event callbacks are done
+ * with ndi mutex held and this can cause a potential deadlock.
+ * Note that cleanup can't fail after deregistration of events.
+ */
+ if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) {
+
+ usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs);
+ }
+
+ iapm = usb_ia->ia_pm;
+
+ mutex_enter(&usb_ia->ia_mutex);
+
+ if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) {
+
+ mutex_exit(&usb_ia->ia_mutex);
+
+ (void) pm_busy_component(dip, 0);
+ if (iapm->uc_wakeup_enabled) {
+
+ /* First bring the device to full power */
+ (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
+
+ rval = usb_handle_remote_wakeup(dip,
+ USB_REMOTE_WAKEUP_DISABLE);
+
+ if (rval != DDI_SUCCESS) {
+ USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
+ usb_ia->ia_log_handle,
+ "usb_cleanup: disable remote "
+ "wakeup failed, rval=%d", rval);
+ }
+ }
+
+ (void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF);
+ (void) pm_idle_component(dip, 0);
+ } else {
+ mutex_exit(&usb_ia->ia_mutex);
+ }
+
+ if (iapm) {
+ kmem_free(iapm, sizeof (usb_common_power_t));
+ }
+
+ /* free children list */
+ if (usb_ia->ia_children_dips) {
+ kmem_free(usb_ia->ia_children_dips,
+ usb_ia->ia_cd_list_length);
+ }
+
+ if (usb_ia->ia_child_events) {
+ kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) *
+ usb_ia->ia_n_ifs);
+ }
+
+ if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) {
+ ddi_remove_minor_node(dip, NULL);
+ }
+
+ mutex_destroy(&usb_ia->ia_mutex);
+
+done:
+ usb_client_detach(dip, usb_ia->ia_dev_data);
+
+ usb_free_log_hdl(usb_ia->ia_log_handle);
+ ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip));
+
+ ddi_prop_remove_all(dip);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * usb_ia_create_children:
+ */
+static void
+usb_ia_create_children(usb_ia_t *usb_ia)
+{
+ usba_device_t *usba_device;
+ uint_t n_ifs, first_if;
+ uint_t i;
+ dev_info_t *cdip;
+
+ usba_device = usba_get_usba_device(usb_ia->ia_dip);
+
+ USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
+ "usb_ia_attach_child_drivers: port = %d, address = %d",
+ usba_device->usb_port, usba_device->usb_addr);
+
+ n_ifs = usb_ia->ia_n_ifs;
+ first_if = usb_ia->ia_first_if;
+
+ /*
+ * create all children if not already present
+ */
+ for (i = 0; i < n_ifs; i++) {
+ if (usb_ia->ia_children_dips[i] != NULL) {
+
+ continue;
+ }
+
+ mutex_exit(&usb_ia->ia_mutex);
+ cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i);
+ mutex_enter(&usb_ia->ia_mutex);
+
+ if (cdip != NULL) {
+ (void) usba_bind_driver(cdip);
+ usb_ia->ia_children_dips[i] = cdip;
+ }
+ }
+
+}
+
+
+/*
+ * event support
+ */
+static int
+usb_ia_busop_get_eventcookie(dev_info_t *dip,
+ dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
+{
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+
+ USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
+ "event=%s", (void *)dip, (void *)rdip, eventname);
+ USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "(dip=%s%d rdip=%s%d)",
+ ddi_driver_name(dip), ddi_get_instance(dip),
+ ddi_driver_name(rdip), ddi_get_instance(rdip));
+
+ /* return event cookie, iblock cookie, and level */
+ return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl,
+ rdip, eventname, cookie, NDI_EVENT_NOPASS));
+}
+
+
+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)
+{
+ int ifno;
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if;
+ mutex_exit(&usb_ia->ia_mutex);
+
+ if (ifno < 0) {
+ ifno = 0;
+ }
+
+ USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p "
+ "cookie=0x%p, cb=0x%p, arg=0x%p",
+ (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
+ USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "(dip=%s%d rdip=%s%d event=%s)",
+ ddi_driver_name(dip), ddi_get_instance(dip),
+ ddi_driver_name(rdip), ddi_get_instance(rdip),
+ ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
+
+ /* Set flag on children registering events */
+ switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) {
+ case USBA_EVENT_TAG_HOT_REMOVAL:
+ mutex_enter(&usb_ia->ia_mutex);
+ usb_ia->ia_child_events[ifno] |=
+ USB_IA_CHILD_EVENT_DISCONNECT;
+ mutex_exit(&usb_ia->ia_mutex);
+
+ break;
+ case USBA_EVENT_TAG_PRE_SUSPEND:
+ mutex_enter(&usb_ia->ia_mutex);
+ usb_ia->ia_child_events[ifno] |=
+ USB_IA_CHILD_EVENT_PRESUSPEND;
+ mutex_exit(&usb_ia->ia_mutex);
+
+ break;
+ default:
+
+ break;
+ }
+ /* add callback (perform registration) */
+ return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl,
+ rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
+}
+
+
+static int
+usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
+{
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+ ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
+
+ ASSERT(cb);
+
+ USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
+ "cookie=0x%p", (void *)dip, cb->ndi_evtcb_dip,
+ cb->ndi_evtcb_cookie);
+ USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "(dip=%s%d rdip=%s%d event=%s)",
+ ddi_driver_name(dip), ddi_get_instance(dip),
+ ddi_driver_name(cb->ndi_evtcb_dip),
+ ddi_get_instance(cb->ndi_evtcb_dip),
+ ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl,
+ cb->ndi_evtcb_cookie));
+
+ /* remove event registration from our event set */
+ return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id));
+}
+
+
+static int
+usb_ia_busop_post_event(dev_info_t *dip,
+ dev_info_t *rdip,
+ ddi_eventcookie_t cookie,
+ void *bus_impldata)
+{
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+
+ USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p "
+ "cookie=0x%p, impl=0x%p",
+ (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
+ USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "(dip=%s%d rdip=%s%d event=%s)",
+ ddi_driver_name(dip), ddi_get_instance(dip),
+ ddi_driver_name(rdip), ddi_get_instance(rdip),
+ ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
+
+ /* post event to all children registered for this event */
+ return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip,
+ cookie, bus_impldata));
+}
+
+
+/*
+ * usb_ia_restore_device_state
+ * set the original configuration of the device
+ */
+static int
+usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia)
+{
+ usb_common_power_t *iapm;
+
+ USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "usb_ia_restore_device_state: usb_ia = %p", usb_ia);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ iapm = usb_ia->ia_pm;
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /* First bring the device to full power */
+ (void) pm_busy_component(dip, 0);
+ (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
+
+ if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0,
+ DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
+
+ /* change the device state from suspended to disconnected */
+ mutex_enter(&usb_ia->ia_mutex);
+ usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
+ mutex_exit(&usb_ia->ia_mutex);
+ (void) pm_idle_component(dip, 0);
+
+ return (USB_FAILURE);
+ }
+
+ /*
+ * if the device had remote wakeup earlier,
+ * enable it again
+ */
+ if (iapm->uc_wakeup_enabled) {
+ (void) usb_handle_remote_wakeup(usb_ia->ia_dip,
+ USB_REMOTE_WAKEUP_ENABLE);
+ }
+
+ mutex_enter(&usb_ia->ia_mutex);
+ usb_ia->ia_dev_state = USB_DEV_ONLINE;
+ mutex_exit(&usb_ia->ia_mutex);
+
+ (void) pm_idle_component(dip, 0);
+
+ return (USB_SUCCESS);
+}
+
+
+/*
+ * usb_ia_event_cb()
+ * handle disconnect and connect events
+ */
+static void
+usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
+ void *arg, void *bus_impldata)
+{
+ int i, tag;
+ usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
+ dev_info_t *child_dip;
+ ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
+
+ USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "usb_ia_event_cb: dip=0x%p, cookie=0x%p, "
+ "arg=0x%p, impl=0x%p",
+ (void *)dip, (void *)cookie, arg, bus_impldata);
+ USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
+ "(dip=%s%d event=%s)",
+ ddi_driver_name(dip), ddi_get_instance(dip),
+ ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
+
+ tag = NDI_EVENT_TAG(cookie);
+ rm_cookie = ndi_event_tag_to_cookie(
+ usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
+ suspend_cookie = ndi_event_tag_to_cookie(
+ usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
+ ins_cookie = ndi_event_tag_to_cookie(
+ usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
+ resume_cookie = ndi_event_tag_to_cookie(
+ usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ switch (tag) {
+ case USBA_EVENT_TAG_HOT_REMOVAL:
+ if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) {
+ USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
+ usb_ia->ia_log_handle,
+ "usb_ia_event_cb: Device already disconnected");
+ } else {
+ /* we are disconnected so set our state now */
+ usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
+ for (i = 0; i < usb_ia->ia_n_ifs; i++) {
+ usb_ia->ia_child_events[i] &= ~
+ USB_IA_CHILD_EVENT_DISCONNECT;
+ }
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /* pass disconnect event to all the children */
+ (void) ndi_event_run_callbacks(
+ usb_ia->ia_ndi_event_hdl, NULL,
+ rm_cookie, bus_impldata);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ }
+ break;
+ case USBA_EVENT_TAG_PRE_SUSPEND:
+ /* set our state *after* suspending children */
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /* pass pre_suspend event to all the children */
+ (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
+ NULL, suspend_cookie, bus_impldata);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ for (i = 0; i < usb_ia->ia_n_ifs; i++) {
+ usb_ia->ia_child_events[i] &= ~
+ USB_IA_CHILD_EVENT_PRESUSPEND;
+ }
+ break;
+ case USBA_EVENT_TAG_HOT_INSERTION:
+ mutex_exit(&usb_ia->ia_mutex);
+ if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) {
+
+ /*
+ * Check to see if this child has missed the disconnect
+ * event before it registered for event cb
+ */
+ mutex_enter(&usb_ia->ia_mutex);
+ for (i = 0; i < usb_ia->ia_n_ifs; i++) {
+ if (usb_ia->ia_child_events[i] &
+ USB_IA_CHILD_EVENT_DISCONNECT) {
+ usb_ia->ia_child_events[i] &=
+ ~USB_IA_CHILD_EVENT_DISCONNECT;
+ child_dip =
+ usb_ia->ia_children_dips[i];
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /* post the missed disconnect */
+ (void) ndi_event_do_callback(
+ usb_ia->ia_ndi_event_hdl,
+ child_dip,
+ rm_cookie,
+ bus_impldata);
+ mutex_enter(&usb_ia->ia_mutex);
+ }
+ }
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /* pass reconnect event to all the children */
+ (void) ndi_event_run_callbacks(
+ usb_ia->ia_ndi_event_hdl, NULL,
+ ins_cookie, bus_impldata);
+
+ }
+ mutex_enter(&usb_ia->ia_mutex);
+ break;
+ case USBA_EVENT_TAG_POST_RESUME:
+ /*
+ * Check to see if this child has missed the pre-suspend
+ * event before it registered for event cb
+ */
+ for (i = 0; i < usb_ia->ia_n_ifs; i++) {
+ if (usb_ia->ia_child_events[i] &
+ USB_IA_CHILD_EVENT_PRESUSPEND) {
+ usb_ia->ia_child_events[i] &=
+ ~USB_IA_CHILD_EVENT_PRESUSPEND;
+ child_dip = usb_ia->ia_children_dips[i];
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /* post the missed pre-suspend event */
+ (void) ndi_event_do_callback(
+ usb_ia->ia_ndi_event_hdl,
+ child_dip, suspend_cookie,
+ bus_impldata);
+ mutex_enter(&usb_ia->ia_mutex);
+ }
+ }
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /* pass post_resume event to all the children */
+ (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
+ NULL, resume_cookie, bus_impldata);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ break;
+ }
+ mutex_exit(&usb_ia->ia_mutex);
+
+}
+
+/*
+ * create the pm components required for power management
+ */
+static void
+usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia)
+{
+ usb_common_power_t *iapm;
+ uint_t pwr_states;
+
+ USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_create_pm_components: Begin");
+
+ /* Allocate the PM state structure */
+ iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
+
+ mutex_enter(&usb_ia->ia_mutex);
+ usb_ia->ia_pm = iapm;
+ iapm->uc_usb_statep = usb_ia;
+ iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
+ iapm->uc_current_power = USB_DEV_OS_FULL_PWR;
+ mutex_exit(&usb_ia->ia_mutex);
+
+ /*
+ * By not enabling parental notification, PM enforces
+ * "strict parental dependency" meaning, usb_ia won't
+ * power off until any of its children are in full power.
+ */
+
+ /*
+ * there are 3 scenarios:
+ * 1. a well behaved device should have remote wakeup
+ * at interface and device level. If the interface
+ * wakes up, usb_ia will wake up
+ * 2. if the device doesn't have remote wake up and
+ * the interface has, PM will still work, ie.
+ * the interfaces wakes up and usb_ia wakes up
+ * 3. if neither the interface nor device has remote
+ * wakeup, the interface will wake up when it is opened
+ * and goes to sleep after being closed for a while
+ * In this case usb_ia should also go to sleep shortly
+ * thereafter
+ * In all scenarios it doesn't really matter whether
+ * remote wakeup at the device level is enabled or not
+ * but we do it anyways
+ */
+ if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
+ USB_SUCCESS) {
+ USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_create_pm_components: "
+ "Remote Wakeup Enabled");
+ iapm->uc_wakeup_enabled = 1;
+ }
+
+ if (usb_create_pm_components(dip, &pwr_states) ==
+ USB_SUCCESS) {
+ iapm->uc_pwr_states = (uint8_t)pwr_states;
+ (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
+ }
+
+ USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
+ "usb_ia_create_pm_components: End");
+}
+
+
+/*
+ * usb_ia_obtain_state:
+ */
+static usb_ia_t *
+usb_ia_obtain_state(dev_info_t *dip)
+{
+ int instance = ddi_get_instance(dip);
+ usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance);
+
+ ASSERT(statep != NULL);
+
+ return (statep);
+}
diff --git a/usr/src/uts/common/io/usb/usb_mid/usb_mid.c b/usr/src/uts/common/io/usb/usb_mid/usb_mid.c
index f814538f98..5f8a1ead10 100644
--- a/usr/src/uts/common/io/usb/usb_mid/usb_mid.c
+++ b/usr/src/uts/common/io/usb/usb_mid/usb_mid.c
@@ -131,6 +131,7 @@ static int usb_mid_bus_ctl(dev_info_t *, dev_info_t *,
static int usb_mid_power(dev_info_t *, int, int);
static int usb_mid_restore_device_state(dev_info_t *, usb_mid_t *);
static usb_mid_t *usb_mid_obtain_state(dev_info_t *);
+static void usb_mid_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
/*
* Busops vector
@@ -200,12 +201,6 @@ static void *usb_mid_statep;
*/
static void usb_mid_create_children(usb_mid_t *usb_mid);
static int usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid);
-static void usb_mid_register_events(usb_mid_t *usb_mid);
-static void usb_mid_unregister_events(usb_mid_t *usb_mid);
-
-/* usbai private */
-char *usba_get_mfg_prod_sn_str(dev_info_t *dip,
- char *buffer, int buflen);
/*
* event definition
@@ -467,7 +462,7 @@ usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
dev_info_t *cdip, *mdip;
int interface, circular_count;
- int rval = NDI_SUCCESS;
+ int rval = NDI_SUCCESS;
USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
"usb_mid_bus_unconfig: op=%d", op);
@@ -496,12 +491,13 @@ usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
/* update children's list */
mutex_enter(&usb_mid->mi_mutex);
for (interface = 0; usb_mid->mi_children_dips &&
- (interface < usb_mid->mi_n_ifs); interface++) {
+ (interface < usb_mid->mi_n_ifs) &&
+ (usb_mid->mi_children_ifs[interface]); interface++) {
mdip = usb_mid->mi_children_dips[interface];
/* now search if this dip still exists */
for (cdip = ddi_get_child(dip); cdip && (cdip != mdip);
- cdip = ddi_get_next_sibling(cdip));
+ cdip = ddi_get_next_sibling(cdip));
if (cdip != mdip) {
/* we lost the dip on this interface */
@@ -524,106 +520,15 @@ usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
return (rval);
}
-/*
- * functions to handle power transition for OS levels 0 -> 3
- */
-static int
-usb_mid_pwrlvl0(usb_mid_t *usb_mid)
-{
- int rval;
-
- switch (usb_mid->mi_dev_state) {
- case USB_DEV_ONLINE:
- /* Issue USB D3 command to the device here */
- rval = usb_set_device_pwrlvl3(usb_mid->mi_dip);
- ASSERT(rval == USB_SUCCESS);
-
- usb_mid->mi_dev_state = USB_DEV_PWRED_DOWN;
- usb_mid->mi_pm->mip_current_power =
- USB_DEV_OS_PWR_OFF;
- /* FALLTHRU */
- case USB_DEV_DISCONNECTED:
- case USB_DEV_SUSPENDED:
- /* allow a disconnected/cpr'ed device to go to low pwr */
-
- return (USB_SUCCESS);
- case USB_DEV_PWRED_DOWN:
- default:
- return (USB_FAILURE);
- }
-}
-
-
-/* ARGSUSED */
-static int
-usb_mid_pwrlvl1(usb_mid_t *usb_mid)
-{
- int rval;
-
- /* Issue USB D2 command to the device here */
- rval = usb_set_device_pwrlvl2(usb_mid->mi_dip);
- ASSERT(rval == USB_SUCCESS);
-
- return (USB_FAILURE);
-}
-
-
-/* ARGSUSED */
-static int
-usb_mid_pwrlvl2(usb_mid_t *usb_mid)
-{
- int rval;
-
- /* Issue USB D1 command to the device here */
- rval = usb_set_device_pwrlvl1(usb_mid->mi_dip);
- ASSERT(rval == USB_SUCCESS);
-
- return (USB_FAILURE);
-}
-
-
-static int
-usb_mid_pwrlvl3(usb_mid_t *usb_mid)
-{
- int rval;
-
- switch (usb_mid->mi_dev_state) {
- case USB_DEV_PWRED_DOWN:
- /* Issue USB D0 command to the device here */
- rval = usb_set_device_pwrlvl0(usb_mid->mi_dip);
- ASSERT(rval == USB_SUCCESS);
-
- usb_mid->mi_dev_state = USB_DEV_ONLINE;
- usb_mid->mi_pm->mip_current_power = USB_DEV_OS_FULL_PWR;
-
- /* FALLTHRU */
- case USB_DEV_ONLINE:
- /* we are already in full power */
-
- /* FALLTHRU */
- case USB_DEV_DISCONNECTED:
- case USB_DEV_SUSPENDED:
- /* allow a disconnected/cpr'ed device to go to low power */
-
- return (USB_SUCCESS);
- default:
- USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
- "usb_mid_pwrlvl3: Illegal state (%s)",
- usb_str_dev_state(usb_mid->mi_dev_state));
-
- return (USB_FAILURE);
- }
-}
-
/* power entry point */
/* ARGSUSED */
static int
usb_mid_power(dev_info_t *dip, int comp, int level)
{
- usb_mid_t *usb_mid;
- usb_mid_power_t *midpm;
- int rval = DDI_FAILURE;
+ usb_mid_t *usb_mid;
+ usb_common_power_t *midpm;
+ int rval = DDI_FAILURE;
usb_mid = usb_mid_obtain_state(dip);
@@ -634,34 +539,21 @@ usb_mid_power(dev_info_t *dip, int comp, int level)
midpm = usb_mid->mi_pm;
/* check if we are transitioning to a legal power level */
- if (USB_DEV_PWRSTATE_OK(midpm->mip_pwr_states, level)) {
+ if (USB_DEV_PWRSTATE_OK(midpm->uc_pwr_states, level)) {
USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
"usb_mid_power: illegal power level = %d "
- "mip_pwr_states = %x", level, midpm->mip_pwr_states);
+ "uc_pwr_states = %x", level, midpm->uc_pwr_states);
mutex_exit(&usb_mid->mi_mutex);
return (rval);
}
- switch (level) {
- case USB_DEV_OS_PWR_OFF:
- rval = usb_mid_pwrlvl0(usb_mid);
- break;
- case USB_DEV_OS_PWR_1:
- rval = usb_mid_pwrlvl1(usb_mid);
- break;
- case USB_DEV_OS_PWR_2:
- rval = usb_mid_pwrlvl2(usb_mid);
- break;
- case USB_DEV_OS_FULL_PWR:
- rval = usb_mid_pwrlvl3(usb_mid);
- break;
- }
+ rval = usba_common_power(dip, midpm, &(usb_mid->mi_dev_state), level);
mutex_exit(&usb_mid->mi_mutex);
- return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
+ return (rval);
}
@@ -673,7 +565,7 @@ usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
int instance = ddi_get_instance(dip);
usb_mid_t *usb_mid = NULL;
- uint_t n_ifs;
+ uint_t n_ifs, i;
size_t size;
switch (cmd) {
@@ -762,6 +654,12 @@ usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
usb_mid->mi_children_dips = kmem_zalloc(size, KM_SLEEP);
usb_mid->mi_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
KM_SLEEP);
+ usb_mid->mi_children_ifs = kmem_zalloc(sizeof (uint_t) * n_ifs,
+ KM_SLEEP);
+ for (i = 0; i < n_ifs; i++) {
+ usb_mid->mi_children_ifs[i] = 1;
+ }
+
/*
* Event handling: definition and registration
* get event handle for events that we have defined
@@ -787,7 +685,7 @@ usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
usb_mid_create_pm_components(dip, usb_mid);
/* event registration for events from our parent */
- usb_mid_register_events(usb_mid);
+ usba_common_register_events(usb_mid->mi_dip, 1, usb_mid_event_cb);
usb_mid->mi_init_state |= USB_MID_EVENTS_REGISTERED;
@@ -854,7 +752,7 @@ usb_mid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
static int
usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
{
- usb_mid_power_t *midpm;
+ usb_common_power_t *midpm;
int rval;
USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
@@ -887,7 +785,7 @@ usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
* Note that cleanup can't fail after deregistration of events.
*/
if (usb_mid->mi_init_state & USB_MID_EVENTS_REGISTERED) {
- usb_mid_unregister_events(usb_mid);
+ usba_common_unregister_events(usb_mid->mi_dip, 1);
}
midpm = usb_mid->mi_pm;
@@ -899,7 +797,7 @@ usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
mutex_exit(&usb_mid->mi_mutex);
(void) pm_busy_component(dip, 0);
- if (midpm->mip_wakeup_enabled) {
+ if (midpm->uc_wakeup_enabled) {
/* First bring the device to full power */
(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
@@ -922,7 +820,7 @@ usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
}
if (midpm) {
- kmem_free(midpm, sizeof (usb_mid_power_t));
+ kmem_free(midpm, sizeof (usb_common_power_t));
}
/* free children list */
@@ -936,6 +834,11 @@ usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
usb_mid->mi_n_ifs);
}
+ if (usb_mid->mi_children_ifs) {
+ kmem_free(usb_mid->mi_children_ifs, sizeof (uint_t) *
+ usb_mid->mi_n_ifs);
+ }
+
if (usb_mid->mi_init_state & USB_MID_MINOR_NODE_CREATED) {
ddi_remove_minor_node(dip, NULL);
}
@@ -959,49 +862,6 @@ done:
}
-int
-usb_mid_devi_bind_driver(usb_mid_t *usb_mid, dev_info_t *dip)
-{
- char *name;
- uint8_t if_num = usba_get_ifno(dip);
- int rval = USB_SUCCESS;
-
- USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
- "usb_mid_devi_bind_driver: dip = 0x%p, if_num = 0x%x", dip, if_num);
-
- name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
-
- /* bind device to the driver */
- if (ndi_devi_bind_driver(dip, 0) != NDI_SUCCESS) {
- /* if we fail to bind report an error */
- (void) usba_get_mfg_prod_sn_str(dip, name, MAXNAMELEN);
- if (name[0] != '\0') {
- if (!usb_owns_device(dip)) {
- USB_DPRINTF_L1(DPRINT_MASK_ATTA,
- usb_mid->mi_log_handle,
- "no driver found for "
- "interface %d (nodename: '%s') of %s",
- if_num, ddi_node_name(dip), name);
- } else {
- USB_DPRINTF_L1(DPRINT_MASK_ATTA,
- usb_mid->mi_log_handle,
- "no driver found for device %s", name);
- }
- } else {
- (void) ddi_pathname(dip, name);
- USB_DPRINTF_L1(DPRINT_MASK_ATTA,
- usb_mid->mi_log_handle,
- "no driver found for device %s", name);
- }
- rval = USB_FAILURE;
- }
-
- kmem_free(name, MAXNAMELEN);
-
- return (rval);
-}
-
-
static void
usb_mid_ugen_attach(usb_mid_t *usb_mid, boolean_t remove_children)
{
@@ -1053,9 +913,9 @@ static void
usb_mid_create_children(usb_mid_t *usb_mid)
{
usba_device_t *usba_device;
- uint_t n_ifs;
- uint_t i;
- dev_info_t *cdip;
+ uint_t n_ifs, if_count;
+ uint_t i, j;
+ dev_info_t *cdip, *ia_dip;
uint_t ugen_bound = 0;
uint_t bound_children = 0;
@@ -1071,6 +931,7 @@ usb_mid_create_children(usb_mid_t *usb_mid)
}
n_ifs = usb_mid->mi_n_ifs;
+ if_count = 1;
USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
"usb_mid_create_children: #interfaces = %d", n_ifs);
@@ -1078,7 +939,14 @@ usb_mid_create_children(usb_mid_t *usb_mid)
/*
* create all children if not already present
*/
- for (i = 0; i < n_ifs; i++) {
+ for (i = 0; i < n_ifs; i += if_count) {
+
+ /* ignore since this if is included by an ia */
+ if (usb_mid->mi_children_ifs[i] == 0) {
+
+ continue;
+ }
+
if (usb_mid->mi_children_dips[i] != NULL) {
if (i_ddi_node_state(
usb_mid->mi_children_dips[i]) >=
@@ -1090,10 +958,36 @@ usb_mid_create_children(usb_mid_t *usb_mid)
}
mutex_exit(&usb_mid->mi_mutex);
+ ia_dip = usba_ready_interface_association_node(usb_mid->mi_dip,
+ i, &if_count);
+
+ if (ia_dip != NULL) {
+ if (usba_bind_driver(ia_dip) == USB_SUCCESS) {
+ bound_children++;
+ if (strcmp(ddi_driver_name(ia_dip),
+ "ugen") == 0) {
+ ugen_bound++;
+ }
+ }
+
+ /*
+ * IA node owns if_count interfaces.
+ * The rest interfaces own none.
+ */
+ mutex_enter(&usb_mid->mi_mutex);
+ usb_mid->mi_children_dips[i] = ia_dip;
+ usb_mid->mi_children_ifs[i] = if_count;
+ for (j = i + 1; j < i + if_count; j++) {
+ usb_mid->mi_children_ifs[j] = 0;
+ }
+
+ continue;
+ }
+
cdip = usba_ready_interface_node(usb_mid->mi_dip, i);
- mutex_enter(&usb_mid->mi_mutex);
+
if (cdip != NULL) {
- if (usb_mid_devi_bind_driver(usb_mid, cdip) ==
+ if (usba_bind_driver(cdip) ==
USB_SUCCESS) {
bound_children++;
if (strcmp(ddi_driver_name(cdip),
@@ -1102,9 +996,17 @@ usb_mid_create_children(usb_mid_t *usb_mid)
}
}
+ /*
+ * interface node owns 1 interface always.
+ */
+ mutex_enter(&usb_mid->mi_mutex);
usb_mid->mi_children_dips[i] = cdip;
+ usb_mid->mi_children_ifs[i] = 1;
+ mutex_exit(&usb_mid->mi_mutex);
}
+
+ mutex_enter(&usb_mid->mi_mutex);
}
usb_mid->mi_removed_children = (bound_children ? B_FALSE : B_TRUE);
@@ -1262,7 +1164,7 @@ usb_mid_busop_post_event(dev_info_t *dip,
static int
usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid)
{
- usb_mid_power_t *midpm;
+ usb_common_power_t *midpm;
USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
"usb_mid_restore_device_state: usb_mid = %p", usb_mid);
@@ -1291,7 +1193,7 @@ usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid)
* if the device had remote wakeup earlier,
* enable it again
*/
- if (midpm->mip_wakeup_enabled) {
+ if (midpm->uc_wakeup_enabled) {
(void) usb_handle_remote_wakeup(usb_mid->mi_dip,
USB_REMOTE_WAKEUP_ENABLE);
}
@@ -1390,8 +1292,9 @@ usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
*/
mutex_enter(&usb_mid->mi_mutex);
for (i = 0; i < usb_mid->mi_n_ifs; i++) {
- if (usb_mid->mi_child_events[i] &
- USB_MID_CHILD_EVENT_DISCONNECT) {
+ if ((usb_mid->mi_child_events[i] &
+ USB_MID_CHILD_EVENT_DISCONNECT) &&
+ usb_mid->mi_children_ifs[i]) {
usb_mid->mi_child_events[i] &=
~USB_MID_CHILD_EVENT_DISCONNECT;
child_dip =
@@ -1427,8 +1330,9 @@ usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
* event before it registered for event cb
*/
for (i = 0; i < usb_mid->mi_n_ifs; i++) {
- if (usb_mid->mi_child_events[i] &
- USB_MID_CHILD_EVENT_PRESUSPEND) {
+ if ((usb_mid->mi_child_events[i] &
+ USB_MID_CHILD_EVENT_PRESUSPEND) &&
+ usb_mid->mi_children_ifs[i]) {
usb_mid->mi_child_events[i] &=
~USB_MID_CHILD_EVENT_PRESUSPEND;
child_dip = usb_mid->mi_children_dips[i];
@@ -1457,145 +1361,25 @@ usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
/*
- * register and unregister for events from our parent
- *
- * Note: usb_mid doesn't use the cookie fields in usba_device structure.
- * They are used/shared by children of usb_mid.
- */
-static void
-usb_mid_register_events(usb_mid_t *usb_mid)
-{
- int rval;
- usba_evdata_t *evdata;
- ddi_eventcookie_t cookie;
-
- USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
- "usb_mid_register_events:");
-
- evdata = usba_get_evdata(usb_mid->mi_dip);
-
- /* get event cookie, discard level and icookie for now */
- rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_REMOVE_EVENT,
- &cookie);
-
- if (rval == DDI_SUCCESS) {
- rval = ddi_add_event_handler(usb_mid->mi_dip,
- cookie, usb_mid_event_cb, NULL, &evdata->ev_rm_cb_id);
-
- if (rval != DDI_SUCCESS) {
-
- goto fail;
- }
- }
- rval = ddi_get_eventcookie(usb_mid->mi_dip, DDI_DEVI_INSERT_EVENT,
- &cookie);
- if (rval == DDI_SUCCESS) {
- rval = ddi_add_event_handler(usb_mid->mi_dip,
- cookie, usb_mid_event_cb, NULL, &evdata->ev_ins_cb_id);
-
- if (rval != DDI_SUCCESS) {
-
- goto fail;
- }
- }
- rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_PRE_SUSPEND_EVENT,
- &cookie);
- if (rval == DDI_SUCCESS) {
- rval = ddi_add_event_handler(usb_mid->mi_dip,
- cookie, usb_mid_event_cb, NULL, &evdata->ev_suspend_cb_id);
-
- if (rval != DDI_SUCCESS) {
-
- goto fail;
- }
- }
- rval = ddi_get_eventcookie(usb_mid->mi_dip, USBA_POST_RESUME_EVENT,
- &cookie);
- if (rval == DDI_SUCCESS) {
- rval = ddi_add_event_handler(usb_mid->mi_dip,
- cookie, usb_mid_event_cb, NULL,
- &evdata->ev_resume_cb_id);
-
- if (rval != DDI_SUCCESS) {
-
- goto fail;
- }
- }
-
- return;
-
-
-fail:
- usb_mid_unregister_events(usb_mid);
-
-}
-
-
-static void
-usb_mid_unregister_events(usb_mid_t *usb_mid)
-{
- int rval;
- usba_evdata_t *evdata;
- usba_device_t *usba_device = usba_get_usba_device(usb_mid->mi_dip);
-
- USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
- "usb_mid_unregister_events:");
-
- evdata = usba_get_evdata(usb_mid->mi_dip);
- if (evdata) {
- if (evdata->ev_rm_cb_id) {
- rval = ddi_remove_event_handler(evdata->ev_rm_cb_id);
- ASSERT(rval == DDI_SUCCESS);
- }
-
- if (evdata->ev_ins_cb_id) {
- rval = ddi_remove_event_handler(evdata->ev_ins_cb_id);
- ASSERT(rval == DDI_SUCCESS);
- }
-
- if (evdata->ev_resume_cb_id) {
- rval =
- ddi_remove_event_handler(evdata->ev_resume_cb_id);
- ASSERT(rval == DDI_SUCCESS);
- }
-
- if (evdata->ev_suspend_cb_id) {
- rval =
- ddi_remove_event_handler(evdata->ev_suspend_cb_id);
- ASSERT(rval == DDI_SUCCESS);
- }
- }
-
- /* clear event data for children, required for cfgmadm unconfigure */
- usba_free_evdata(usba_device->usb_evdata);
- usba_device->usb_evdata = NULL;
- usba_device->rm_cookie = NULL;
- usba_device->ins_cookie = NULL;
- usba_device->suspend_cookie = NULL;
- usba_device->resume_cookie = NULL;
-}
-
-
-/*
* create the pm components required for power management
*/
static void
usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid)
{
- usb_mid_power_t *midpm;
+ usb_common_power_t *midpm;
uint_t pwr_states;
USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
"usb_mid_create_pm_components: Begin");
/* Allocate the PM state structure */
- midpm = kmem_zalloc(sizeof (usb_mid_power_t), KM_SLEEP);
+ midpm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
mutex_enter(&usb_mid->mi_mutex);
usb_mid->mi_pm = midpm;
- midpm->mip_usb_mid = usb_mid;
- midpm->mip_pm_capabilities = 0; /* XXXX should this be 0?? */
- midpm->mip_current_power = USB_DEV_OS_FULL_PWR;
+ midpm->uc_usb_statep = usb_mid;
+ midpm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
+ midpm->uc_current_power = USB_DEV_OS_FULL_PWR;
mutex_exit(&usb_mid->mi_mutex);
/*
@@ -1626,12 +1410,12 @@ usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid)
USB_DPRINTF_L3(DPRINT_MASK_PM, usb_mid->mi_log_handle,
"usb_mid_create_pm_components: "
"Remote Wakeup Enabled");
- midpm->mip_wakeup_enabled = 1;
+ midpm->uc_wakeup_enabled = 1;
}
if (usb_create_pm_components(dip, &pwr_states) ==
USB_SUCCESS) {
- midpm->mip_pwr_states = (uint8_t)pwr_states;
+ midpm->uc_pwr_states = (uint8_t)pwr_states;
(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
}
diff --git a/usr/src/uts/common/io/usb/usba/hcdi.c b/usr/src/uts/common/io/usb/usba/hcdi.c
index 13a72b588f..f4b47dd233 100644
--- a/usr/src/uts/common/io/usb/usba/hcdi.c
+++ b/usr/src/uts/common/io/usb/usba/hcdi.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -195,6 +194,9 @@ usba_hcdi_register(usba_hcdi_register_args_t *args, uint_t flags)
} else if (strcmp(datap, "interface") == 0) {
hcdi->hcdi_ugen_default_binding =
USBA_UGEN_INTERFACE_BINDING;
+ } else if (strcmp(datap, "interface-association") == 0) {
+ hcdi->hcdi_ugen_default_binding =
+ USBA_UGEN_INTERFACE_ASSOCIATION_BINDING;
} else {
USB_DPRINTF_L2(DPRINT_MASK_HCDI,
hcdi->hcdi_log_handle,
diff --git a/usr/src/uts/common/io/usb/usba/parser.c b/usr/src/uts/common/io/usb/usba/parser.c
index e6d1893ebe..f4e0af84e5 100644
--- a/usr/src/uts/common/io/usb/usba/parser.c
+++ b/usr/src/uts/common/io/usb/usba/parser.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -297,6 +296,39 @@ usba_parse_cfg_pwr_descr(
size_t
+usb_parse_ia_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
+ size_t buflen,
+ size_t first_if,
+ usb_ia_descr_t *ret_descr,
+ size_t ret_buf_len)
+{
+ uchar_t *bufend = buf + buflen;
+
+ if ((buf == NULL) || (ret_descr == NULL)) {
+
+ return (USB_PARSE_ERROR);
+ }
+
+ while (buf + USB_IA_DESCR_SIZE <= bufend) {
+ if ((buf[1] == USB_DESCR_TYPE_IA) &&
+ (buf[2] == first_if)) {
+
+ return (usb_parse_data("cccccccc",
+ buf, bufend - buf, ret_descr, ret_buf_len));
+ }
+
+ /*
+ * Check for a bad buffer.
+ * If buf[0] is 0, then this will be an infinite loop
+ */
+ INCREMENT_BUF(buf);
+ }
+
+ return (USB_PARSE_ERROR);
+}
+
+
+size_t
usb_parse_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
size_t buflen,
uint_t if_number,
diff --git a/usr/src/uts/common/io/usb/usba/usba.c b/usr/src/uts/common/io/usb/usba/usba.c
index 27f5cd9cfc..9dd3547609 100644
--- a/usr/src/uts/common/io/usb/usba/usba.c
+++ b/usr/src/uts/common/io/usb/usba/usba.c
@@ -83,7 +83,7 @@ extern struct mod_ops mod_miscops;
struct modlmisc modlmisc = {
&mod_miscops, /* Type of module */
- "USBA: USB Architecture 2.0 %I%"
+ "USBA: USB Architecture 2.0 1.66"
};
struct modlinkage modlinkage = {
@@ -152,6 +152,14 @@ _info(struct modinfo *modinfop)
return (mod_info(&modlinkage, modinfop));
}
+boolean_t
+usba_owns_ia(dev_info_t *dip)
+{
+ int if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "interface-count", 0);
+
+ return ((if_count) ? B_TRUE : B_FALSE);
+}
/*
* common bus ctl for hcd, usb_mid, and hubd
@@ -199,6 +207,14 @@ usba_bus_ctl(dev_info_t *dip,
"usb%x,%x",
usba_device->usb_dev_descr->idVendor,
usba_device->usb_dev_descr->idProduct);
+ } else if (usba_owns_ia(rdip)) {
+ (void) snprintf(compat_name,
+ sizeof (compat_name),
+ "usbia%x,%x.config%x.%x",
+ usba_device->usb_dev_descr->idVendor,
+ usba_device->usb_dev_descr->idProduct,
+ usba_device->usb_cfg_value,
+ usb_get_if_number(rdip));
} else {
(void) snprintf(compat_name,
sizeof (compat_name),
@@ -230,7 +246,9 @@ usba_bus_ctl(dev_info_t *dip,
"%s@%s, %s%d at bus address %d\n",
(usba_device->usb_dev_descr->bcdUSB & 0xff00) >> 8,
usba_device->usb_dev_descr->bcdUSB & 0xff,
- (usb_owns_device(rdip) ? "device" : "interface"),
+ (usb_owns_device(rdip) ? "device" :
+ ((usba_owns_ia(rdip) ? "interface-association" :
+ "interface"))),
compat_name, speed,
(hub_usba_device->usb_dev_descr->bcdUSB &
0xff00) >> 8,
@@ -1386,9 +1404,21 @@ usba_set_usba_device(dev_info_t *dip, usba_device_t *usba_device)
static node_name_entry_t device_node_name_table[] = {
{ USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
{ USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
+{ USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
+{ USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
{ DONTCARE, DONTCARE, DONTCARE, "device" }
};
+/* interface-association node table */
+static node_name_entry_t ia_node_name_table[] = {
+{ USB_CLASS_AUDIO, DONTCARE, DONTCARE, "audio" },
+{ USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
+{ USB_CLASS_WIRELESS, USB_SUBCLS_WUSB_2, USB_PROTO_WUSB_DWA,
+ "device-wire-adaptor" },
+{ USB_CLASS_WIRELESS, DONTCARE, DONTCARE, "wireless-controller" },
+{ DONTCARE, DONTCARE, DONTCARE, "interface-association" }
+};
+
/* interface node table, refer to section 3.3.2.1 */
static node_name_entry_t if_node_name_table[] = {
{ USB_CLASS_AUDIO, USB_SUBCLS_AUD_CONTROL, DONTCARE, "sound-control" },
@@ -1403,7 +1433,7 @@ static node_name_entry_t if_node_name_table[] = {
{ USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
{ USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
{ USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
-{ USB_CLASS_COMM, DONTCARE, DONTCARE, "control" },
+{ USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
{ USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
{ USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
@@ -1413,6 +1443,8 @@ static node_name_entry_t if_node_name_table[] = {
{ USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
+{ USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
+
{ USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
{ USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
@@ -1421,6 +1453,10 @@ static node_name_entry_t if_node_name_table[] = {
{ USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
+{ USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
+{ USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
+{ USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
+
{ USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
{ USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
{ USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
@@ -1443,7 +1479,7 @@ static node_name_entry_t combined_node_name_table[] = {
{ USB_CLASS_COMM, USB_SUBCLS_CDCC_ISDN, DONTCARE, "isdn" },
{ USB_CLASS_COMM, USB_SUBCLS_CDCC_ETHERNET, DONTCARE, "ethernet" },
{ USB_CLASS_COMM, USB_SUBCLS_CDCC_ATM_NETWORK, DONTCARE, "atm-network" },
-{ USB_CLASS_COMM, DONTCARE, DONTCARE, "control" },
+{ USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
{ USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_KEYBOARD, "keyboard" },
{ USB_CLASS_HID, USB_SUBCLS_HID_1, USB_PROTO_HID_MOUSE, "mouse" },
@@ -1451,25 +1487,41 @@ static node_name_entry_t combined_node_name_table[] = {
{ USB_CLASS_PHYSICAL, DONTCARE, DONTCARE, "physical" },
+{ USB_CLASS_IMAGE, DONTCARE, DONTCARE, "image" },
+
{ USB_CLASS_PRINTER, DONTCARE, DONTCARE, "printer" },
+{ USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_RBC_T10, DONTCARE, "storage" },
+{ USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8020I, DONTCARE, "cdrom" },
+{ USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_QIC_157, DONTCARE, "tape" },
+{ USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_UFI, DONTCARE, "floppy" },
+{ USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SFF8070I, DONTCARE, "storage" },
+{ USB_CLASS_MASS_STORAGE, USB_SUBCLS_MS_SCSI, DONTCARE, "storage" },
{ USB_CLASS_MASS_STORAGE, DONTCARE, DONTCARE, "storage" },
{ USB_CLASS_CDC_DATA, DONTCARE, DONTCARE, "data" },
{ USB_CLASS_SECURITY, DONTCARE, DONTCARE, "security" },
+{ USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_CONTROL, DONTCARE, "video-control" },
+{ USB_CLASS_VIDEO, USB_SUBCLS_VIDEO_STREAM, DONTCARE, "video-stream" },
+{ USB_CLASS_VIDEO, DONTCARE, DONTCARE, "video" },
+
{ USB_CLASS_APP, USB_SUBCLS_APP_FIRMWARE, DONTCARE, "firmware" },
{ USB_CLASS_APP, USB_SUBCLS_APP_IRDA, DONTCARE, "IrDa" },
{ USB_CLASS_APP, USB_SUBCLS_APP_TEST, DONTCARE, "test" },
-{ USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
{ USB_CLASS_COMM, DONTCARE, DONTCARE, "communications" },
-{ DONTCARE, DONTCARE, DONTCARE, "device" },
+{ USB_CLASS_HUB, DONTCARE, DONTCARE, "hub" },
+{ USB_CLASS_DIAG, DONTCARE, DONTCARE, "diagnostics" },
+{ USB_CLASS_MISC, DONTCARE, DONTCARE, "miscellaneous" },
+{ DONTCARE, DONTCARE, DONTCARE, "device" }
};
static size_t device_node_name_table_size =
sizeof (device_node_name_table)/sizeof (struct node_name_entry);
+static size_t ia_node_name_table_size =
+ sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
static size_t if_node_name_table_size =
sizeof (if_node_name_table)/sizeof (struct node_name_entry);
static size_t combined_node_name_table_size =
@@ -1485,6 +1537,11 @@ usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
node_name_entry_t *node_name_table;
switch (flag) {
+ /* interface share node names with interface-association */
+ case FLAG_INTERFACE_ASSOCIATION_NODE:
+ node_name_table = ia_node_name_table;
+ size = ia_node_name_table_size;
+ break;
case FLAG_INTERFACE_NODE:
node_name_table = if_node_name_table;
size = if_node_name_table_size;
@@ -1511,6 +1568,7 @@ usba_set_node_name(dev_info_t *dip, uint8_t class, uint8_t subclass,
((s == DONTCARE) || (s == subclass)) &&
((p == DONTCARE) || (p == protocol))) {
char *name = node_name_table[i].name;
+
(void) ndi_devi_set_nodename(dip, name, 0);
break;
}
@@ -2094,6 +2152,248 @@ usba_ready_device_node(dev_info_t *child_dip)
/*
+ * driver binding at interface association level. the first arg is the parent
+ * dip. if_count returns amount of interfaces which are associated within
+ * this interface-association that starts from first_if.
+ */
+/*ARGSUSED*/
+dev_info_t *
+usba_ready_interface_association_node(dev_info_t *dip,
+ uint_t first_if,
+ uint_t *if_count)
+{
+ dev_info_t *child_dip = NULL;
+ usba_device_t *child_ud = usba_get_usba_device(dip);
+ usb_dev_descr_t *usb_dev_descr;
+ size_t usb_cfg_length;
+ uchar_t *usb_cfg;
+ usb_ia_descr_t ia_descr;
+ int i, n, rval;
+ int reg[2];
+ size_t size;
+ usb_port_status_t port_status;
+ char *force_bind = NULL;
+
+ usb_cfg = usb_get_raw_cfg_data(dip, &usb_cfg_length);
+
+ mutex_enter(&child_ud->usb_mutex);
+
+ usb_dev_descr = child_ud->usb_dev_descr;
+
+ /*
+ * for each interface association, determine all compatible names
+ */
+ USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
+ "usba_ready_ia_node: "
+ "port %d, interface = %d, port_status = %x",
+ child_ud->usb_port, first_if, child_ud->usb_port_status);
+
+ /* Parse the interface descriptor */
+ size = usb_parse_ia_descr(
+ usb_cfg,
+ usb_cfg_length,
+ first_if, /* interface index */
+ &ia_descr,
+ USB_IA_DESCR_SIZE);
+
+ *if_count = 1;
+ if (size != USB_IA_DESCR_SIZE) {
+ USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
+ "parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
+ size, USB_IA_DESCR_SIZE);
+ mutex_exit(&child_ud->usb_mutex);
+
+ return (NULL);
+ }
+
+ port_status = child_ud->usb_port_status;
+
+ /* create reg property */
+ reg[0] = first_if;
+ reg[1] = child_ud->usb_cfg_value;
+
+ mutex_exit(&child_ud->usb_mutex);
+
+ /* clone this dip */
+ rval = usba_create_child_devi(dip,
+ "interface-association",
+ NULL, /* usba_hcdi ops */
+ NULL, /* root hub dip */
+ port_status, /* port status */
+ child_ud, /* share this usba_device */
+ &child_dip);
+
+ if (rval != USB_SUCCESS) {
+
+ goto fail;
+ }
+
+ rval = ndi_prop_update_int_array(
+ DDI_DEV_T_NONE, child_dip, "reg", reg, 2);
+
+ if (rval != DDI_PROP_SUCCESS) {
+
+ goto fail;
+ }
+
+ usba_set_node_name(child_dip, ia_descr.bFunctionClass,
+ ia_descr.bFunctionSubClass, ia_descr.bFunctionProtocol,
+ FLAG_INTERFACE_ASSOCIATION_NODE);
+
+ /* check force binding */
+ if (usba_ugen_force_binding ==
+ USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
+ force_bind = "ugen";
+ }
+
+ /*
+ * check whether there is another dip with this name and address
+ */
+ ASSERT(usba_find_existing_node(child_dip) == NULL);
+
+ mutex_enter(&usba_mutex);
+ n = 0;
+
+ if (force_bind) {
+ (void) ndi_devi_set_nodename(child_dip, force_bind, 0);
+ (void) strncpy(usba_name[n++], force_bind,
+ USBA_MAX_COMPAT_NAME_LEN);
+ }
+
+ /* 1) usbiaVID,PID.REV.configCN.FN */
+ (void) sprintf(usba_name[n++],
+ "usbia%x,%x.%x.config%x.%x",
+ usb_dev_descr->idVendor,
+ usb_dev_descr->idProduct,
+ usb_dev_descr->bcdDevice,
+ child_ud->usb_cfg_value,
+ first_if);
+
+ /* 2) usbiaVID,PID.configCN.FN */
+ (void) sprintf(usba_name[n++],
+ "usbia%x,%x.config%x.%x",
+ usb_dev_descr->idVendor,
+ usb_dev_descr->idProduct,
+ child_ud->usb_cfg_value,
+ first_if);
+
+
+ if (ia_descr.bFunctionClass) {
+ /* 3) usbiaVID,classFC.FSC.FPROTO */
+ (void) sprintf(usba_name[n++],
+ "usbia%x,class%x.%x.%x",
+ usb_dev_descr->idVendor,
+ ia_descr.bFunctionClass,
+ ia_descr.bFunctionSubClass,
+ ia_descr.bFunctionProtocol);
+
+ /* 4) usbiaVID,classFC.FSC */
+ (void) sprintf(usba_name[n++],
+ "usbia%x,class%x.%x",
+ usb_dev_descr->idVendor,
+ ia_descr.bFunctionClass,
+ ia_descr.bFunctionSubClass);
+
+ /* 5) usbiaVID,classFC */
+ (void) sprintf(usba_name[n++],
+ "usbia%x,class%x",
+ usb_dev_descr->idVendor,
+ ia_descr.bFunctionClass);
+
+ /* 6) usbia,classFC.FSC.FPROTO */
+ (void) sprintf(usba_name[n++],
+ "usbia,class%x.%x.%x",
+ ia_descr.bFunctionClass,
+ ia_descr.bFunctionSubClass,
+ ia_descr.bFunctionProtocol);
+
+ /* 7) usbia,classFC.FSC */
+ (void) sprintf(usba_name[n++],
+ "usbia,class%x.%x",
+ ia_descr.bFunctionClass,
+ ia_descr.bFunctionSubClass);
+
+ /* 8) usbia,classFC */
+ (void) sprintf(usba_name[n++],
+ "usbia,class%x",
+ ia_descr.bFunctionClass);
+ }
+
+ if (usba_get_ugen_binding(child_dip) ==
+ USBA_UGEN_INTERFACE_ASSOCIATION_BINDING) {
+ /* 9) ugen */
+ (void) sprintf(usba_name[n++], "ugen");
+ } else {
+
+ (void) sprintf(usba_name[n++], "usb,ia");
+ }
+
+ for (i = 0; i < n; i += 2) {
+ USB_DPRINTF_L3(DPRINT_MASK_USBA, usba_log_handle,
+ "compatible name:\t%s\t%s", usba_compatible[i],
+ (((i+1) < n)? usba_compatible[i+1] : ""));
+ }
+ mutex_exit(&usba_mutex);
+
+ /* create compatible property */
+ if (n) {
+ rval = ndi_prop_update_string_array(
+ DDI_DEV_T_NONE, child_dip,
+ "compatible", (char **)usba_compatible,
+ n);
+
+ if (rval != DDI_PROP_SUCCESS) {
+
+ goto fail;
+ }
+ }
+
+ /* update the address property */
+ rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
+ "assigned-address", child_ud->usb_addr);
+ if (rval != DDI_PROP_SUCCESS) {
+ USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
+ "usba_ready_interface_node: address update failed");
+ }
+
+ /* create property with first interface number */
+ rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
+ "interface", ia_descr.bFirstInterface);
+
+ if (rval != DDI_PROP_SUCCESS) {
+
+ goto fail;
+ }
+
+ /* create property with the count of interfaces in this ia */
+ rval = ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
+ "interface-count", ia_descr.bInterfaceCount);
+
+ if (rval != DDI_PROP_SUCCESS) {
+
+ goto fail;
+ }
+
+ USB_DPRINTF_L2(DPRINT_MASK_USBA, usba_log_handle,
+ "%s%d port %d: %s, dip = 0x%p",
+ ddi_node_name(ddi_get_parent(dip)),
+ ddi_get_instance(ddi_get_parent(dip)),
+ child_ud->usb_port, ddi_node_name(child_dip), child_dip);
+
+ *if_count = ia_descr.bInterfaceCount;
+ usba_set_usba_device(child_dip, child_ud);
+ ASSERT(!mutex_owned(&(usba_get_usba_device(child_dip)->usb_mutex)));
+
+ return (child_dip);
+
+fail:
+ (void) usba_destroy_child_devi(child_dip, NDI_DEVI_REMOVE);
+
+ return (NULL);
+}
+
+
+/*
* driver binding at interface level, the first arg will be the
* the parent dip
*/
@@ -2184,12 +2484,10 @@ usba_ready_interface_node(dev_info_t *dip, uint_t intf)
force_bind = "ugen";
}
-#ifdef DEBUG
/*
* check whether there is another dip with this name and address
*/
ASSERT(usba_find_existing_node(child_dip) == NULL);
-#endif
mutex_enter(&usba_mutex);
n = 0;
diff --git a/usr/src/uts/common/io/usb/usba/usbai_util.c b/usr/src/uts/common/io/usb/usba/usbai_util.c
index b9f979f86f..899a8eb444 100644
--- a/usr/src/uts/common/io/usb/usba/usbai_util.c
+++ b/usr/src/uts/common/io/usb/usba/usbai_util.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -35,6 +34,8 @@
#include <sys/usb/usba/usba_impl.h>
#include <sys/usb/usba/hcdi_impl.h>
+extern void usba_free_evdata(usba_evdata_t *);
+
static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
/* local functions */
@@ -815,6 +816,21 @@ usb_owns_device(dev_info_t *dip)
}
+/* check whether the interface is in this interface association */
+boolean_t
+usba_check_if_in_ia(dev_info_t *dip, int n_if)
+{
+ int first_if, if_count;
+
+ first_if = usb_get_if_number(dip);
+ if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+ DDI_PROP_DONTPASS, "interface-count", -1);
+ if_count += first_if;
+
+ return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE);
+}
+
+
uint8_t
usba_get_ifno(dev_info_t *dip)
{
@@ -917,8 +933,8 @@ usba_sync_set_alt_if(dev_info_t *dip,
"uf=0x%x", ddi_node_name(dip), interface,
alt_number, flags);
- /* if we don't own the device, we must own the interface */
- if (!usb_owns_device(dip) &&
+ /* if we don't own the device, we must own the interface or ia */
+ if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) &&
(interface != usb_get_if_number(dip))) {
usba_release_ph_data(ph_data->p_ph_impl);
@@ -2177,3 +2193,242 @@ usba_test_allocb(size_t size, uint_t pri)
}
}
#endif
+
+
+/*
+ * usb common power management for usb_mid, usb_ia and maybe other simple
+ * drivers.
+ */
+
+/*
+ * functions to handle power transition for OS levels 0 -> 3
+ */
+static int
+usb_common_pwrlvl0(dev_info_t *dip, usb_common_power_t *pm, int *dev_state)
+{
+ int rval;
+
+ switch (*dev_state) {
+ case USB_DEV_ONLINE:
+ /* Issue USB D3 command to the device here */
+ rval = usb_set_device_pwrlvl3(dip);
+ ASSERT(rval == USB_SUCCESS);
+
+ *dev_state = USB_DEV_PWRED_DOWN;
+ pm->uc_current_power = USB_DEV_OS_PWR_OFF;
+ /* FALLTHRU */
+ case USB_DEV_DISCONNECTED:
+ case USB_DEV_SUSPENDED:
+ /* allow a disconnected/cpr'ed device to go to low pwr */
+
+ return (USB_SUCCESS);
+ case USB_DEV_PWRED_DOWN:
+ default:
+ return (USB_FAILURE);
+ }
+}
+
+
+/* ARGSUSED */
+static int
+usb_common_pwrlvl1(dev_info_t *dip, usb_common_power_t *pm, int *dev_state)
+{
+ int rval;
+
+ /* Issue USB D2 command to the device here */
+ rval = usb_set_device_pwrlvl2(dip);
+ ASSERT(rval == USB_SUCCESS);
+
+ return (USB_FAILURE);
+}
+
+
+/* ARGSUSED */
+static int
+usb_common_pwrlvl2(dev_info_t *dip, usb_common_power_t *pm, int *dev_state)
+{
+ int rval;
+
+ /* Issue USB D1 command to the device here */
+ rval = usb_set_device_pwrlvl1(dip);
+ ASSERT(rval == USB_SUCCESS);
+
+ return (USB_FAILURE);
+}
+
+
+static int
+usb_common_pwrlvl3(dev_info_t *dip, usb_common_power_t *pm, int *dev_state)
+{
+ int rval;
+
+ switch (*dev_state) {
+ case USB_DEV_PWRED_DOWN:
+ /* Issue USB D0 command to the device here */
+ rval = usb_set_device_pwrlvl0(dip);
+ ASSERT(rval == USB_SUCCESS);
+
+ *dev_state = USB_DEV_ONLINE;
+ pm->uc_current_power = USB_DEV_OS_FULL_PWR;
+
+ /* FALLTHRU */
+ case USB_DEV_ONLINE:
+ /* we are already in full power */
+
+ /* FALLTHRU */
+ case USB_DEV_DISCONNECTED:
+ case USB_DEV_SUSPENDED:
+ /* allow a disconnected/cpr'ed device to go to low power */
+
+ return (USB_SUCCESS);
+ default:
+ USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
+ "usb_common_pwrlvl3: Illegal state (%s)",
+ usb_str_dev_state(*dev_state));
+
+ return (USB_FAILURE);
+ }
+}
+
+/* power management */
+int
+usba_common_power(dev_info_t *dip, usb_common_power_t *pm, int *dev_state,
+ int level)
+{
+ int rval = DDI_FAILURE;
+
+ switch (level) {
+ case USB_DEV_OS_PWR_OFF:
+ rval = usb_common_pwrlvl0(dip, pm, dev_state);
+ break;
+ case USB_DEV_OS_PWR_1:
+ rval = usb_common_pwrlvl1(dip, pm, dev_state);
+ break;
+ case USB_DEV_OS_PWR_2:
+ rval = usb_common_pwrlvl2(dip, pm, dev_state);
+ break;
+ case USB_DEV_OS_FULL_PWR:
+ rval = usb_common_pwrlvl3(dip, pm, dev_state);
+ break;
+ }
+
+ return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+/*
+ * register and unregister for events from our parent for usb_mid and usb_ia
+ * and maybe other nexus driver.
+ *
+ * Note: The cookie fields in usba_device structure is not used. They are
+ * used/shared by children.
+ */
+void
+usba_common_register_events(dev_info_t *dip, uint_t if_num,
+ void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *))
+{
+ int rval;
+ usba_evdata_t *evdata;
+ ddi_eventcookie_t cookie;
+
+ USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
+ "usb_common_register_events:");
+
+ evdata = usba_get_evdata(dip);
+
+ /* get event cookie, discard level and icookie for now */
+ rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
+ &cookie);
+
+ if (rval == DDI_SUCCESS) {
+ rval = ddi_add_event_handler(dip,
+ cookie, event_cb, NULL, &evdata->ev_rm_cb_id);
+
+ if (rval != DDI_SUCCESS) {
+
+ goto fail;
+ }
+ }
+ rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
+ &cookie);
+ if (rval == DDI_SUCCESS) {
+ rval = ddi_add_event_handler(dip, cookie, event_cb,
+ NULL, &evdata->ev_ins_cb_id);
+
+ if (rval != DDI_SUCCESS) {
+
+ goto fail;
+ }
+ }
+ rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie);
+ if (rval == DDI_SUCCESS) {
+ rval = ddi_add_event_handler(dip,
+ cookie, event_cb, NULL, &evdata->ev_suspend_cb_id);
+
+ if (rval != DDI_SUCCESS) {
+
+ goto fail;
+ }
+ }
+ rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie);
+ if (rval == DDI_SUCCESS) {
+ rval = ddi_add_event_handler(dip, cookie, event_cb, NULL,
+ &evdata->ev_resume_cb_id);
+
+ if (rval != DDI_SUCCESS) {
+
+ goto fail;
+ }
+ }
+
+ return;
+
+
+fail:
+ usba_common_unregister_events(dip, if_num);
+
+}
+
+void
+usba_common_unregister_events(dev_info_t *dip, uint_t if_num)
+{
+ usba_evdata_t *evdata;
+ usba_device_t *usba_device = usba_get_usba_device(dip);
+ int i;
+
+ evdata = usba_get_evdata(dip);
+
+ if (evdata->ev_rm_cb_id != NULL) {
+ (void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
+ evdata->ev_rm_cb_id = NULL;
+ }
+
+ if (evdata->ev_ins_cb_id != NULL) {
+ (void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
+ evdata->ev_ins_cb_id = NULL;
+ }
+
+ if (evdata->ev_suspend_cb_id != NULL) {
+ (void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
+ evdata->ev_suspend_cb_id = NULL;
+ }
+
+ if (evdata->ev_resume_cb_id != NULL) {
+ (void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
+ evdata->ev_resume_cb_id = NULL;
+ }
+
+ /* clear event data for children, required for cfgmadm unconfigure */
+ if (usb_owns_device(dip)) {
+ usba_free_evdata(usba_device->usb_evdata);
+ usba_device->usb_evdata = NULL;
+ usba_device->rm_cookie = NULL;
+ usba_device->ins_cookie = NULL;
+ usba_device->suspend_cookie = NULL;
+ usba_device->resume_cookie = NULL;
+ } else {
+ for (i = 0; i < if_num; i++) {
+ usba_device->usb_client_flags[usba_get_ifno(dip) + i]
+ &= ~USBA_CLIENT_FLAG_EV_CBS;
+ }
+ }
+}
diff --git a/usr/src/uts/common/io/warlock/usb_ia.wlcmd b/usr/src/uts/common/io/warlock/usb_ia.wlcmd
new file mode 100644
index 0000000000..c0c370f9bb
--- /dev/null
+++ b/usr/src/uts/common/io/warlock/usb_ia.wlcmd
@@ -0,0 +1,32 @@
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+one usb_ia
+one usba_device
+
+### currently unused functions
+root usb_ia_event_cb
+root usb_ia_power
+root usb_ia_bus_ctl
diff --git a/usr/src/uts/common/io/warlock/usb_ia_with_usba.wlcmd b/usr/src/uts/common/io/warlock/usb_ia_with_usba.wlcmd
new file mode 100644
index 0000000000..6fbe635964
--- /dev/null
+++ b/usr/src/uts/common/io/warlock/usb_ia_with_usba.wlcmd
@@ -0,0 +1,172 @@
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+
+one ohci_state
+one ehci_state
+one uhci_state
+one usb_ia
+one usba_device
+
+### specify the root functions
+
+root usba_ascii_string_descr
+root usb_console_output_init
+root usb_console_output_fini
+root usb_console_output_enter
+root usb_console_output_exit
+root usb_console_write
+root usb_console_input_enter
+root usb_console_input_exit
+root usb_console_input_fini
+root usb_console_input_init
+root usb_console_read
+root hubd_hotplug_thread
+root hubd_cpr_post_user_callb
+root usb_get_dev_descr
+root usb_get_if_number
+root usb_parse_CV_cfg_descr
+root usb_parse_CV_ep_descr
+root usb_parse_CV_if_descr
+root usb_pipe_reset
+root usb_pipe_get_private
+root usb_get_current_frame_number
+root usb_get_max_isoc_pkts
+root usb_pipe_set_private
+root usba_ready_interface_node
+root usba_free_hcdi_ops
+root ohci_intr
+root ehci_intr
+
+root usba_dbuf_tail
+root usb_log
+root usb_ia_event_cb
+root hubd_bus_power
+root usba_hubdi_power
+root usba_hubdi_root_hub_power
+root usba_hubdi_bus_ctl
+root usb_set_device_pwrlvl0
+root usb_set_device_pwrlvl1
+root usb_set_device_pwrlvl2
+root usb_set_device_pwrlvl3
+root usba_async_req_raise_power
+root usba_async_req_lower_power
+root usb_req_raise_power
+root usb_req_lower_power
+root usb_is_pm_enabled
+root usb_pipe_bulk_transfer_size
+root usba_get_hotplug_stats
+root usba_reset_hotplug_stats
+root usb_async_req
+root usb_get_ep_data
+root usba_pipe_get_policy
+root usb_pipe_ctrl_xfer_wait
+root usb_get_current_cfgidx
+
+root usb_alloc_bulk_req
+root usb_clear_feature
+root usb_free_bulk_req
+root usb_get_alt_if
+root usb_get_ep_descr
+root usb_get_if_descr
+root usb_pipe_bulk_xfer
+root usb_pipe_isoc_xfer
+root usb_pipe_stop_isoc_polling
+root usb_set_alt_if
+root usb_set_cfg
+root usb_get_cfg
+root usb_get_status
+root usb_ep_num
+root usb_register_event_cbs
+root usb_unregister_event_cbs
+root usb_log_descr_tree
+root usb_print_descr_tree
+root usb_pipe_drain_reqs
+root usb_try_serialize_access
+root usb_fini_serialization
+root usb_init_serialization
+root usb_release_access
+root usb_serialize_access
+root usb_rval2errno
+root usb_clr_feature
+root usb_get_ep_data
+root usb_register_hotplug_cbs
+root usb_register_client
+root usb_ugen_power
+root usb_ugen_attach
+root usb_ugen_close
+root usb_ugen_detach
+root usb_ugen_disconnect_ev_cb
+root usb_ugen_get_hdl
+root usb_ugen_open
+root usb_ugen_poll
+root usb_ugen_read
+root usb_ugen_reconnect_ev_cb
+root usb_ugen_write
+root usba_ready_interface_association_node
+
+
+root hubd_root_hub_cleanup_thread
+root hubd_restore_state_cb
+root hubd_disconnect_event_cb
+root hubd_post_resume_event_cb
+root hubd_pre_suspend_event_cb
+root hubd_reconnect_event_cb
+
+
+root hcdi_autoclearing
+root hcdi_cb_thread
+root hcdi_shared_cb_thread
+
+
+root usba_pipe_do_async_func_thread
+root usba_get_hc_dma_attr
+root usba_hcdi_get_req_private
+root usba_hcdi_set_req_private
+root usba_move_list
+root usba_taskq_destroy
+root usba_mk_mctl
+root usb_fail_checkpoint
+
+add usb_bulk_req::bulk_cb targets warlock_dummy
+add usb_bulk_req::bulk_exc_cb targets warlock_dummy
+add usb_ctrl_req::ctrl_cb targets warlock_dummy
+add usb_ctrl_req::ctrl_exc_cb targets warlock_dummy
+add usb_isoc_req::isoc_cb targets warlock_dummy
+add usb_isoc_req::isoc_exc_cb targets warlock_dummy
+add usba_pipe_async_req::sync_func targets warlock_dummy
+
+add usba_pm_req::cb targets warlock_dummy
+
+add usba_pipe_async_req::callback targets warlock_dummy
+
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_ctrl_td
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_bulk_td
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_intr_td
+add ohci_trans_wrapper::tw_handle_td targets ohci_handle_isoc_td
+
+add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_ctrl_qtd
+add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_bulk_qtd
+add ehci_trans_wrapper::tw_handle_qtd targets ehci_handle_intr_qtd
diff --git a/usr/src/uts/common/sys/usb/usb_ia/usb_iavar.h b/usr/src/uts/common/sys/usb/usb_ia/usb_iavar.h
new file mode 100644
index 0000000000..bb7194dcf7
--- /dev/null
+++ b/usr/src/uts/common/sys/usb/usb_ia/usb_iavar.h
@@ -0,0 +1,114 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_USB_USB_IA_H
+#define _SYS_USB_USB_IA_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/usb/usba/usbai_private.h>
+
+/*
+ * soft state information for this usb_ia
+ */
+typedef struct usb_ia {
+ int ia_instance;
+
+ uint_t ia_init_state;
+
+ kmutex_t ia_mutex;
+
+ /*
+ * dev_info_t reference
+ */
+ dev_info_t *ia_dip;
+
+ /* pointer to usb_ia_power_t */
+ usb_common_power_t *ia_pm;
+
+ int ia_dev_state;
+
+ int ia_first_if;
+ int ia_n_ifs;
+
+ /* track event registration of children */
+ uint8_t *ia_child_events;
+ /*
+ * ia_children_dips is a array for holding
+ * each child dip indexed by interface number
+ */
+ dev_info_t **ia_children_dips;
+
+ size_t ia_cd_list_length;
+
+ /* logging of messages */
+ usb_log_handle_t ia_log_handle;
+
+ /* usb registration */
+ usb_client_dev_data_t *ia_dev_data;
+
+ /* event support */
+ ndi_event_hdl_t ia_ndi_event_hdl;
+
+} usb_ia_t;
+
+_NOTE(MUTEX_PROTECTS_DATA(usb_ia::ia_mutex, usb_ia))
+_NOTE(MUTEX_PROTECTS_DATA(usb_ia::ia_mutex, usb_common_power_t))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia::ia_instance
+ usb_ia::ia_ndi_event_hdl
+ usb_ia::ia_dev_data
+ usb_ia::ia_log_handle
+ usb_ia::ia_dip
+ usb_ia::ia_pm))
+
+/* init state */
+#define USB_IA_LOCK_INIT 0x0001
+#define USB_IA_MINOR_NODE_CREATED 0x0002
+#define USB_IA_EVENTS_REGISTERED 0x0004
+
+/* Tracking events registered by children */
+#define USB_IA_CHILD_EVENT_DISCONNECT 0x01
+#define USB_IA_CHILD_EVENT_PRESUSPEND 0x02
+
+/*
+ * Debug printing
+ * Masks
+ */
+#define DPRINT_MASK_ATTA 0x00000001
+#define DPRINT_MASK_CBOPS 0x00000002
+#define DPRINT_MASK_EVENTS 0x00000004
+#define DPRINT_MASK_PM 0x00000010
+#define DPRINT_MASK_ALL 0xFFFFFFFF
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_USB_USB_IA_H */
diff --git a/usr/src/uts/common/sys/usb/usb_mid/usb_midvar.h b/usr/src/uts/common/sys/usb/usb_mid/usb_midvar.h
index 3668fbcc5d..65409ee966 100644
--- a/usr/src/uts/common/sys/usb/usb_mid/usb_midvar.h
+++ b/usr/src/uts/common/sys/usb/usb_mid/usb_midvar.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -18,8 +17,9 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- *
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,26 +34,6 @@ extern "C" {
#include <sys/usb/usba/usbai_private.h>
-typedef struct usb_mid_power_struct {
- void *mip_usb_mid; /* points back to usb_mid_t */
-
- uint8_t mip_wakeup_enabled;
-
- /* this is the bit mask of the power states that device has */
- uint8_t mip_pwr_states;
-
- /* wakeup and power transistion capabilites of an interface */
- uint8_t mip_pm_capabilities;
-
- uint8_t mip_current_power; /* current power level */
-} usb_mid_power_t;
-
-/* warlock directives, stable data */
-_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_power_t::mip_usb_mid))
-_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_power_t::mip_wakeup_enabled))
-_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_power_t::mip_pwr_states))
-_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_power_t::mip_pm_capabilities))
-
/*
* soft state information for this usb_mid
@@ -71,8 +51,8 @@ typedef struct usb_mid {
*/
dev_info_t *mi_dip;
- /* pointer to usb_mid_power_t */
- usb_mid_power_t *mi_pm;
+ /* pointer to usb_common_power_t */
+ usb_common_power_t *mi_pm;
/*
* save the usba_device pointer
@@ -87,11 +67,16 @@ typedef struct usb_mid {
/* track event registration of children */
uint8_t *mi_child_events;
+
+ /* record the interface num of each child node */
+ uint_t *mi_children_ifs;
+
/*
- * mi_children_dips is a array for holding
+ * mi_children_dips is an array for holding
* each child dip indexed by interface number
*/
dev_info_t **mi_children_dips;
+
boolean_t mi_removed_children;
size_t mi_cd_list_length;
@@ -112,7 +97,7 @@ typedef struct usb_mid {
} usb_mid_t;
_NOTE(MUTEX_PROTECTS_DATA(usb_mid::mi_mutex, usb_mid))
-_NOTE(MUTEX_PROTECTS_DATA(usb_mid::mi_mutex, usb_mid_power_t))
+_NOTE(MUTEX_PROTECTS_DATA(usb_mid::mi_mutex, usb_common_power_t))
_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid::mi_instance
usb_mid::mi_ndi_event_hdl
usb_mid::mi_dev_data
diff --git a/usr/src/uts/common/sys/usb/usba/usba_impl.h b/usr/src/uts/common/sys/usb/usba/usba_impl.h
index 5a5e50516c..b0d29f6316 100644
--- a/usr/src/uts/common/sys/usb/usba/usba_impl.h
+++ b/usr/src/uts/common/sys/usb/usba/usba_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -47,6 +46,7 @@ extern "C" {
*/
#define USBA_UGEN_DEVICE_BINDING 1
#define USBA_UGEN_INTERFACE_BINDING 2
+#define USBA_UGEN_INTERFACE_ASSOCIATION_BINDING 3
/*
* Allocating a USB address
@@ -345,6 +345,7 @@ _NOTE(SCHEME_PROTECTS_DATA("USBA managed data", usba_log_handle_impl))
#define FLAG_INTERFACE_NODE 0
#define FLAG_DEVICE_NODE 1
#define FLAG_COMBINED_NODE 2
+#define FLAG_INTERFACE_ASSOCIATION_NODE 3
typedef struct node_name_entry {
int16_t class;
diff --git a/usr/src/uts/common/sys/usb/usba/usba_private.h b/usr/src/uts/common/sys/usb/usba/usba_private.h
index b681e273d1..baeb84fb66 100644
--- a/usr/src/uts/common/sys/usb/usba/usba_private.h
+++ b/usr/src/uts/common/sys/usb/usba/usba_private.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -71,9 +70,10 @@ extern "C" {
* ret_descr buffer the data is to be returned in
* ret_buf_len size of the buffer at ret_descr
*
- * if_index the index in the array of concurrent interfaces
+ * first_if the first interace associated with current iad
+ * if_index the index in the array of concurrent interfaces
* supported by this configuration
- * alt_if_setting alternate setting for the interface identified
+ * alt_if_setting alternate setting for the interface identified
* by if_index
* ep_index the index in the array of endpoints supported by
* this configuration
@@ -100,6 +100,14 @@ size_t usb_parse_cfg_descr(
size_t ret_buf_len);
+size_t usb_parse_ia_descr(
+ uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
+ size_t buflen,
+ size_t first_if,
+ usb_ia_descr_t *ret_descr,
+ size_t ret_buf_len);
+
+
size_t usb_parse_if_descr(
uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
size_t buflen,
@@ -281,10 +289,15 @@ ddi_dma_attr_t *usba_get_hc_dma_attr(dev_info_t *dip);
*/
int usba_bind_driver(dev_info_t *);
+/* check whether the dip owns an interface-associaiton */
+boolean_t usba_owns_ia(dev_info_t *dip);
+
/*
* Driver binding functions
*/
dev_info_t *usba_ready_device_node(dev_info_t *);
+dev_info_t *usba_ready_interface_association_node(dev_info_t *,
+ uint_t, uint_t *);
dev_info_t *usba_ready_interface_node(dev_info_t *, uint_t);
/* Some Nexus driver functions. */
@@ -345,6 +358,7 @@ extern usb_ep_descr_t usba_default_ep_descr;
#define USB_IF_DESCR_SIZE 9 /* interface descr size */
#define USBA_IF_PWR_DESCR_SIZE 15 /* interface pwr descr size */
#define USB_EP_DESCR_SIZE 7 /* endpoint descr size */
+#define USB_IA_DESCR_SIZE 8 /* interface association descr size */
/*
* For compatibility with old code.
@@ -410,6 +424,45 @@ size_t usba_parse_if_pwr_descr(uchar_t *, size_t buflen, uint_t,
*/
size_t usba_ascii_string_descr(uchar_t *, size_t, char *, size_t);
+
+/*
+ * usb common power management, for usb_mid, usb_ia and maybe other simple
+ * drivers.
+ */
+typedef struct usb_common_power_struct {
+ void *uc_usb_statep; /* points back to state structure */
+
+ uint8_t uc_wakeup_enabled;
+
+ /* this is the bit mask of the power states that device has */
+ uint8_t uc_pwr_states;
+
+ /* wakeup and power transition capabilites of an interface */
+ uint8_t uc_pm_capabilities;
+
+ uint8_t uc_current_power; /* current power level */
+} usb_common_power_t;
+
+/* warlock directives, stable data */
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_common_power_t::uc_usb_statep))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_common_power_t::uc_wakeup_enabled))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_common_power_t::uc_pwr_states))
+_NOTE(DATA_READABLE_WITHOUT_LOCK(usb_common_power_t::uc_pm_capabilities))
+
+/* power management */
+int usba_common_power(dev_info_t *, usb_common_power_t *, int *, int);
+
+/*
+ * usb common events handler for usb_mid, usb_ia and maybe other nexus
+ * drivers.
+ */
+
+void usba_common_register_events(dev_info_t *, uint_t,
+ void (*)(dev_info_t *, ddi_eventcookie_t, void *, void *));
+
+void usba_common_unregister_events(dev_info_t *, uint_t);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/usb/usbai.h b/usr/src/uts/common/sys/usb/usbai.h
index 43958caef9..1bea82b9d1 100644
--- a/usr/src/uts/common/sys/usb/usbai.h
+++ b/usr/src/uts/common/sys/usb/usbai.h
@@ -317,6 +317,22 @@ typedef struct usb_other_speed_cfg_descr {
/*
+ * usb_ia_descr:
+ * usb interface association descriptor, refer to USB 2.0 ECN(IAD)
+ */
+typedef struct usb_ia_descr {
+ uint8_t bLength; /* descriptor size */
+ uint8_t bDescriptorType; /* INTERFACE_ASSOCIATION */
+ uint8_t bFirstInterface; /* 1st interface number */
+ uint8_t bInterfaceCount; /* number of interfaces */
+ uint8_t bFunctionClass; /* class code */
+ uint8_t bFunctionSubClass; /* sub class code */
+ uint8_t bFunctionProtocol; /* protocol code */
+ uint8_t iFunction; /* description string */
+} usb_ia_descr_t;
+
+
+/*
* usb_if_descr:
* usb interface descriptor, refer to USB 2.0/9.6.5
*/
@@ -1326,6 +1342,7 @@ typedef struct usb_ctrl_req {
#define USB_DESCR_TYPE_DEV_QLF 0x06
#define USB_DESCR_TYPE_OTHER_SPEED_CFG 0x07
#define USB_DESCR_TYPE_IF_PWR 0x08
+#define USB_DESCR_TYPE_IA 0x0B
/*
* device request type
@@ -2335,14 +2352,16 @@ void usb_unregister_hotplug_cbs(dev_info_t *dip);
#define USB_CLASS_CDC_CTRL 2 /* CDC-control iface class, also 2 */
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
+#define USB_CLASS_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9 /* Device class */
#define USB_CLASS_CDC_DATA 10
#define USB_CLASS_CCID 11
#define USB_CLASS_SECURITY 13
+#define USB_CLASS_VIDEO 14
#define USB_CLASS_DIAG 220 /* Device class */
-#define USB_CLASS_WIRELESS 224 /* Device class */
+#define USB_CLASS_WIRELESS 224
#define USB_CLASS_MISC 239 /* Device class */
#define USB_CLASS_APP 254
#define USB_CLASS_VENDOR_SPEC 255 /* Device class */
@@ -2393,7 +2412,17 @@ void usb_unregister_hotplug_cbs(dev_info_t *dip);
#define USB_SUBCLS_APP_IRDA 0x02 /* app spec IrDa subclass */
#define USB_SUBCLS_APP_TEST 0x03 /* app spec test subclass */
-
+/* Video subclasses */
+#define USB_SUBCLS_VIDEO_CONTROL 0x01 /* video control */
+#define USB_SUBCLS_VIDEO_STREAM 0x02 /* video stream */
+#define USB_SUBCLS_VIDEO_COLLECTION 0x03 /* video interface collection */
+
+/* Wireless controller subclasses and protocols */
+#define USB_SUBCLS_WUSB_1 0x01
+#define USB_SUBCLS_WUSB_2 0x02
+#define USB_PROTO_WUSB_HWA 0x01 /* host wire adapter */
+#define USB_PROTO_WUSB_DWA 0x02 /* device wire adapter */
+#define USB_PROTO_WUSB_DWA_ISO 0x03 /* device wire adapter isoc */
#ifdef __cplusplus
}
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index 749ccf7d77..f02a017c55 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -374,6 +374,7 @@ DRV_KMODS += uhci
DRV_KMODS += ehci
DRV_KMODS += ohci
DRV_KMODS += usb_mid
+DRV_KMODS += usb_ia
DRV_KMODS += scsa2usb
DRV_KMODS += usbprn
DRV_KMODS += ugen
diff --git a/usr/src/uts/intel/usb_ia/Makefile b/usr/src/uts/intel/usb_ia/Makefile
new file mode 100644
index 0000000000..cb1dc5321e
--- /dev/null
+++ b/usr/src/uts/intel/usb_ia/Makefile
@@ -0,0 +1,149 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/intel/usb_ia/Makefile
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# This makefile drives the production of the usb_ia driver kernel module.
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = usb_ia
+OBJECTS = $(USB_IA_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(USB_IA_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+WARLOCK_OUT = $(USB_IA_OBJS:%.o=%.ll)
+WARLOCK_OK = $(MODULE).ok
+WLCMD_DIR = $(UTSBASE)/common/io/warlock
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Override defaults to build a unique, local modstubs.o.
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+CLEANFILES += $(MODSTUBS_O)
+
+#
+# depends on misc/usba
+#
+LDFLAGS += -dy -Nmisc/usba
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+ $(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+clobber: $(CLOBBER_DEPS)
+ $(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
+
+#
+# Defines for local commands.
+#
+WARLOCK = warlock
+WLCC = wlcc
+TOUCH = touch
+SCCS = sccs
+TEST = test
+
+#
+# lock_lint rules
+#
+USBA_FILES = $(USBA_OBJS:%.o=../usba/%.ll)
+UHCI_FILES = $(UHCI_OBJS:%.o=../uhci/%.ll)
+OHCI_FILES = $(OHCI_OBJS:%.o=../ohci/%.ll)
+EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll)
+
+warlock: $(WARLOCK_OK) warlock_with_usba
+
+%.wlcmd:
+ cd $(WLCMD_DIR); $(TEST) -f $@ || $(SCCS) get $@
+
+$(WARLOCK_OK): $(WARLOCK_OUT) usb_ia.wlcmd warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/usb_ia.wlcmd $(WARLOCK_OUT) \
+ -l ../warlock/ddi_dki_impl.ll
+ $(TOUCH) $@
+
+%.ll: $(UTSBASE)/common/io/usb/usb_ia/%.c \
+ $(UTSBASE)/common/sys/usb/usb_ia/usb_iavar.h
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_with_usba: usb_ia_with_usba.wlcmd $(WARLOCK_OUT) usba_files \
+ ohci_files ehci_files uhci_files warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/usb_ia_with_usba.wlcmd \
+ $(USBA_FILES) $(OHCI_FILES) $(EHCI_FILES) $(UHCI_FILES) \
+ $(WARLOCK_OUT) \
+ -l ../warlock/ddi_dki_impl.ll
+
+usba_files:
+ @cd ../usba;pwd; $(MAKE) warlock
+
+uhci_files:
+ @cd ../uhci;pwd; $(MAKE) warlock
+
+ohci_files:
+ @cd ../ohci;pwd; $(MAKE) warlock
+
+ehci_files:
+ @cd ../ehci;pwd; $(MAKE) warlock
+
+warlock_ddi.files:
+ cd ../warlock; pwd; $(MAKE) warlock
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 5d394d8f6f..97c3f7789d 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -267,7 +267,7 @@ DRV_KMODS += bge bpp eri esp fas hme
DRV_KMODS += openeepr options sd ses st
DRV_KMODS += ssd
DRV_KMODS += ecpp
-DRV_KMODS += hid hubd ehci ohci uhci usb_mid scsa2usb usbprn ugen
+DRV_KMODS += hid hubd ehci ohci uhci usb_mid usb_ia scsa2usb usbprn ugen
DRV_KMODS += usbser usbsacm usbsksp usbsprl
DRV_KMODS += usb_as usb_ac
DRV_KMODS += usbskel
diff --git a/usr/src/uts/sparc/usb_ia/Makefile b/usr/src/uts/sparc/usb_ia/Makefile
new file mode 100644
index 0000000000..0eebba45de
--- /dev/null
+++ b/usr/src/uts/sparc/usb_ia/Makefile
@@ -0,0 +1,148 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# uts/sparc/usb_ia/Makefile
+
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# This makefile drives the production of the usb_ia driver kernel module.
+# sparc architecture dependent
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = usb_ia
+OBJECTS = $(USB_IA_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(USB_IA_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+WARLOCK_OUT = $(USB_IA_OBJS:%.o=%.ll)
+WARLOCK_OK = $(MODULE).ok
+WLCMD_DIR = $(UTSBASE)/common/io/warlock
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+# lint pass one enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# depends on misc/usba
+#
+LDFLAGS += -dy -Nmisc/usba
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+.KEEP_STATE:
+
+all: $(ALL_DEPS)
+
+def: $(DEF_DEPS)
+
+clean: $(CLEAN_DEPS)
+ $(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+clobber: $(CLOBBER_DEPS)
+ $(RM) $(WARLOCK_OUT) $(WARLOCK_OK)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
+
+#
+# Defines for local commands.
+#
+WARLOCK = warlock
+WLCC = wlcc
+TOUCH = touch
+SCCS = sccs
+TEST = test
+
+#
+# lock_lint rules
+#
+USBA_FILES = $(USBA_OBJS:%.o=../usba/%.ll)
+UHCI_FILES = $(UHCI_OBJS:%.o=../uhci/%.ll)
+OHCI_FILES = $(OHCI_OBJS:%.o=../ohci/%.ll)
+EHCI_FILES = $(EHCI_OBJS:%.o=../ehci/%.ll)
+
+warlock: $(WARLOCK_OK) warlock_with_usba
+
+%.wlcmd:
+ cd $(WLCMD_DIR); $(TEST) -f $@ || $(SCCS) get $@
+
+$(WARLOCK_OK): $(WARLOCK_OUT) usb_ia.wlcmd warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/usb_ia.wlcmd $(WARLOCK_OUT) \
+ -l ../warlock/ddi_dki_impl.ll
+ $(TOUCH) $@
+
+%.ll: $(UTSBASE)/common/io/usb/usb_ia/%.c \
+ $(UTSBASE)/common/sys/usb/usb_ia/usb_iavar.h
+ $(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_with_usba: usb_ia_with_usba.wlcmd $(WARLOCK_OUT) usba_files \
+ ohci_files ehci_files uhci_files warlock_ddi.files
+ $(WARLOCK) -c $(WLCMD_DIR)/usb_ia_with_usba.wlcmd \
+ $(USBA_FILES) $(OHCI_FILES) $(EHCI_FILES) $(UHCI_FILES) \
+ $(WARLOCK_OUT) \
+ -l ../warlock/ddi_dki_impl.ll
+
+
+usba_files:
+ @cd ../usba;pwd; $(MAKE) warlock
+
+uhci_files:
+ @cd ../uhci;pwd; $(MAKE) warlock
+
+ohci_files:
+ @cd ../ohci;pwd; $(MAKE) warlock
+
+ehci_files:
+ @cd ../ehci;pwd; $(MAKE) warlock
+
+warlock_ddi.files:
+ cd ../warlock; pwd; $(MAKE) warlock
diff --git a/usr/src/uts/sparc/warlock/Makefile b/usr/src/uts/sparc/warlock/Makefile
index a0de441e35..ccb3e4f575 100644
--- a/usr/src/uts/sparc/warlock/Makefile
+++ b/usr/src/uts/sparc/warlock/Makefile
@@ -77,6 +77,7 @@ warlock.usb:
@cd ../usb_ah; make clean; $(MAKE) warlock
@cd ../ugen; make clean; $(MAKE) warlock
@cd ../usb_mid; make clean; $(MAKE) warlock
+ @cd ../usb_ia; make clean; $(MAKE) warlock
@cd ../usbprn; make clean; $(MAKE) warlock
@cd ../usbser; make clean; $(MAKE) warlock
@cd $(CLOSED)/uts/sparc/usbser_edge; make clean; $(MAKE) warlock