/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2016 James S. Blachly, MD <james.blachly@gmail.com>
*/
/*
* USBA: Solaris USB Architecture support
*/
#define USBA_FRAMEWORK
/*
* USBA private variables and tunables
*/
/* mutex to protect usba_root_hubs */
typedef struct usba_root_hub_ent {
/*
* ddivs forced binding:
*
* usbc usbc_xhubs usbc_xaddress node name
*
* 0 x x class name or "device"
*
* 1 0 0 ddivs_usbc
* 1 0 >1 ddivs_usbc except device
* at usbc_xaddress
* 1 1 0 ddivs_usbc except hubs
* 1 1 >1 ddivs_usbc except hubs and
* device at usbc_xaddress
*/
/*
* compatible name handling
*/
/*
* allowing for 15 compat names, plus one force bind name and
* one possible specified client driver name
*/
/* double linked list for usba_devices */
/*
* modload support
*/
&mod_miscops, /* Type of module */
"USBA: USB Architecture 2.0 1.66"
};
};
extern usb_log_handle_t hubdi_log_handle;
int
_init(void)
{
int rval;
/*
* usbai providing log support needs to be init'ed first
* and destroyed last
*/
}
return (rval);
}
int
_fini()
{
int rval;
}
return (rval);
}
int
{
}
{
"interface-count", 0);
}
/*
* common bus ctl for hcd, usb_mid, and hubd
*/
int
void *arg,
void *result)
{
switch (op) {
case DDI_CTLOPS_REPORTDEV:
{
/* find the parent hub */
!(usba_is_root_hub(hubdip))) {
}
if (usba_device) {
if (usb_owns_device(rdip)) {
(void) snprintf(compat_name,
sizeof (compat_name),
"usb%x,%x",
} else if (usba_owns_ia(rdip)) {
(void) snprintf(compat_name,
sizeof (compat_name),
"usbia%x,%x.config%x.%x",
} else {
(void) snprintf(compat_name,
sizeof (compat_name),
"usbif%x,%x.config%x.%x",
}
switch (usba_device->usb_port_status) {
case USBA_HIGH_SPEED_DEV:
speed = "hi speed (USB 2.x)";
break;
case USBA_LOW_SPEED_DEV:
speed = "low speed (USB 1.x)";
break;
case USBA_FULL_SPEED_DEV:
default:
speed = "full speed (USB 1.x)";
break;
}
"?USB %x.%x %s (%s) operating at %s on "
"USB %x.%x %s hub: "
"%s@%s, %s%d at bus address %d\n",
"interface"))),
0xff00) >> 8,
if (name[0] != '\0') {
}
} else { /* harden USBA against this case; if it happens */
"?USB-device: %s@%s, %s%d\n",
}
return (DDI_SUCCESS);
}
case DDI_CTLOPS_INITCHILD:
{
int usb_addr;
uint_t n;
int *data;
int rval;
/*
* as long as the dip exists, it should have
* usba_device structure associated with it
*/
if (usba_device == NULL) {
"usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
return (DDI_NOT_WELL_FORMED);
}
/* the dip should have an address and reg property */
"usba_bus_ctl:\n\t"
"%s%d %s%d op=%d rdip = 0x%p dip = 0x%p",
"usba_bus_ctl: DDI_NOT_WELL_FORMED (%s (0x%p))",
return (DDI_NOT_WELL_FORMED);
}
DDI_PROP_DONTPASS, "reg",
&data, &n)) != DDI_SUCCESS) {
"usba_bus_ctl: %d, DDI_NOT_WELL_FORMED", rval);
return (DDI_NOT_WELL_FORMED);
}
/*
* if the configuration is 1, the unit address is
* just the interface number
*/
} else {
}
/*
* increment the reference count for each child using this
* usba_device structure
*/
"usba_bus_ctl: init usba_device = 0x%p ref_count = %d",
return (DDI_SUCCESS);
}
case DDI_CTLOPS_UNINITCHILD:
{
if (usba_device != NULL) {
/*
* decrement the reference count for each child
* using this usba_device structure
*/
"usba_hcdi_bus_ctl: uninit usba_device=0x%p "
"ref_count=%d",
}
return (DDI_SUCCESS);
}
case DDI_CTLOPS_IOMIN:
/* Do nothing */
return (DDI_SUCCESS);
/*
* These ops correspond to functions that "shouldn't" be called
* by a USB client driver. So we whine when we're called.
*/
case DDI_CTLOPS_DMAPMAPC:
case DDI_CTLOPS_REPORTINT:
case DDI_CTLOPS_REGSIZE:
case DDI_CTLOPS_NREGS:
case DDI_CTLOPS_SIDDEV:
case DDI_CTLOPS_SLAVEONLY:
case DDI_CTLOPS_AFFINITY:
case DDI_CTLOPS_POKE:
case DDI_CTLOPS_PEEK:
return (DDI_FAILURE);
/*
*/
default:
}
}
/*
* initialize and destroy USBA module
*/
void
{
&usba_errmask, NULL, 0);
usba_log_handle, "usba_usba_initialization");
}
void
{
}
/*
* usba_set_usb_address:
* set usb address in usba_device structure
*/
int
{
uchar_t s = 8;
char *usb_address_in_use;
continue;
}
"usba_set_usb_address: %d", address);
return (USB_SUCCESS);
}
usba_device->usb_addr = 0;
"no usb address available");
return (USB_FAILURE);
}
/*
* usba_unset_usb_address:
* unset usb_address in usba_device structure
*/
void
{
uchar_t s = 8;
char *usb_address_in_use;
if (address > ROOT_HUB_ADDR) {
"usba_unset_usb_address: address=%d", address);
usba_device->usb_addr = 0;
}
}
struct usba_evdata *
{
/* called when dip attaches */
while (evdata) {
return (evdata);
}
}
return (evdata);
}
/*
* allocate a usb device structure and link it in the list
*/
{
int ep_idx;
/*
* create a new usba_device structure
*/
/*
* initialize usba_device
*/
/*
* add to list of usba_devices
*/
/* init mutex in each usba_ph_impl structure */
}
"allocated usba_device 0x%p", (void *)usba_device);
return (usba_device);
}
/* free NDI event data associated with usba_device */
void
{
while (evdata) {
}
}
/*
* free usb device structure
*/
void
{
int i, ep_idx;
if (usba_device == NULL) {
return;
}
if (usba_device->usb_ref_count) {
return;
}
"usba_free_usba_device 0x%p, address=0x%x, ref cnt=%d",
if (ph_data) {
}
}
/* destroy mutex in each usba_ph_impl structure */
}
(void) usba_rm_from_list(&usba_device_list,
"deallocating usba_device = 0x%p, address = 0x%x",
/*
* ohci allocates descriptors for root hub so we can't
* deallocate these here
*/
if (usba_device->usb_cfg_array) {
"deallocating usb_config_array: 0x%p",
(void *)usba_device->usb_cfg_array);
for (i = 0;
i++) {
if (usba_device->usb_cfg_array[i]) {
usba_device->usb_cfg_array[i],
usba_device->usb_cfg_array_len[i]);
}
}
/* free the array pointers */
}
if (usba_device->usb_cfg_str_descr) {
"deallocating usb_cfg_str_descr: 0x%p",
(void *)usba_device->usb_cfg_str_descr);
for (i = 0;
i++) {
if (usba_device->usb_cfg_str_descr[i]) {
usb_cfg_str_descr[i]) + 1);
}
}
/* free the array pointers */
}
if (usba_device->usb_dev_descr) {
sizeof (usb_dev_descr_t));
}
if (usba_device->usb_mfg_str) {
}
if (usba_device->usb_product_str) {
}
if (usba_device->usb_serialno_str) {
}
}
#ifndef __lock_lint
#endif
if (usba_device->usb_client_flags) {
#ifndef __lock_lint
int i;
for (i = 0; i < usba_device->usb_n_ifs; i++) {
}
#endif
}
if (usba_device->usb_client_attach_list) {
sizeof (*usba_device->usb_client_attach_list));
}
if (usba_device->usb_client_ev_cb_list) {
sizeof (*usba_device->usb_client_ev_cb_list));
}
/*
* finally ready to destroy the structure
*/
}
/* clear the data toggle for all endpoints on this device */
void
{
int i;
if (usba_device != NULL) {
for (i = 0; i < USBA_N_ENDPOINTS; i++) {
}
}
}
/*
* usba_create_child_devi():
* create a child devinfo node, usba_device, attach properties.
* the usba_device structure is shared between all interfaces
*/
int
char *node_name,
{
int usba_device_allocated = 0;
"usba_create_child_devi: %s usba_device=0x%p "
"port status=0x%x", node_name,
(void *)usba_device, port_status);
"child dip=0x%p", (void *)*child_dip);
if (usba_device == NULL) {
/* grab the mutex to keep warlock happy */
} else {
if (usba_hcdi_ops) {
}
if (usb_root_hub_dip) {
}
}
if (usba_device->usb_addr == 0) {
address = 0;
"cannot set usb address for dip=0x%p",
(void *)*child_dip);
goto fail;
}
}
/* attach properties */
"assigned-address", address);
if (rval != DDI_PROP_SUCCESS) {
"cannot set usb address property for dip=0x%p",
(void *)*child_dip);
rval = USB_FAILURE;
goto fail;
}
/*
* store the usba_device point in the dip
*/
"usba_create_child_devi: devi=0x%p (%s) ud=0x%p",
(void *)usba_device);
return (USB_SUCCESS);
fail:
if (*child_dip) {
}
if (usba_device_allocated) {
} else if (address && usba_device) {
}
"usba_create_child_devi failed: rval=%d", rval);
return (rval);
}
int
{
"usba_destroy_child_devi: %s%d (0x%p)",
/*
* if the child hasn't been bound yet, we can just
* free the dip
*/
/*
* do not call ndi_devi_free() since it might
* deadlock
*/
} else {
"usba_destroy_child_devi:\n\t"
"offlining dip 0x%p usba_device=0x%p (%s)", (void *)dip,
(void *)usba_device, devnm);
if (rval != NDI_SUCCESS) {
" ndi_devi_unconfig_one %s%d failed (%d)",
rval);
}
}
"usba_destroy_child_devi: rval=%d", rval);
}
/*
* list management
*/
void
{
}
void
{
}
void
{
int remaining;
/* check if it is not in another list */
#ifdef DEBUG
/*
* only verify the list when not in interrupt context, we
* have to trust the HCD
*/
if (!servicing_interrupt()) {
/* check if not already in this list */
"Attempt to corrupt USB list at 0x%p",
(void *)head);
goto done;
}
remaining--;
/*
* Detect incorrect circ links or found
* unexpected elements.
*/
panic("Corrupted USB list at 0x%p",
(void *)head);
/*NOTREACHED*/
}
}
}
#endif
} else {
/* add to tail */
}
"usba_add_to_list: head=0x%p element=0x%p count=%d",
done:
}
int
{
int found = 0;
int remaining;
/* find the element in the list first */
"usba_rm_from_list: head=0x%p element=0x%p count=%d",
while (e) {
if (e == element) {
found++;
break;
}
e = e->next;
remaining--;
/* Detect incorrect circ links or found unexpected elements. */
if ((e && (remaining == 0)) ||
/*NOTREACHED*/
}
}
if (!found) {
return (USB_FAILURE);
}
/* now remove the element */
}
}
}
}
} else {
}
} else {
}
"usba_rm_from_list success: head=0x%p element=0x%p cnt=%d",
return (USB_SUCCESS);
}
{
if (head) {
if (element) {
/* now remove the element */
}
}
}
} else {
}
} else {
}
"usba_rm_first_from_list: head=0x%p el=0x%p cnt=%d",
}
return (element);
}
{
if (element) {
}
return (private);
}
/*
* move list to new list and zero original list
*/
void
{
}
int
{
int remaining;
rval = USB_SUCCESS;
break;
}
remaining--;
/* Detect incorrect circ links or found unexpected elements. */
/*NOTREACHED*/
}
}
return (rval);
}
int
{
int count = 0;
int remaining;
count++;
remaining--;
/* Detect incorrect circ links or found unexpected elements. */
/*NOTREACHED*/
}
}
if (count) {
"usba_list_entry_count: leaking %d", count);
}
return (count);
}
int
{
int count;
return (count);
}
/* add a new root hub to the usba_root_hubs list */
void
{
hub = (usba_root_hub_ent_t *)
}
/* remove a root hub from the usba_root_hubs list */
void
{
hubp = &usba_root_hubs;
while (*hubp) {
return;
}
}
}
/*
* check whether this dip is the root hub. Any root hub known by
* usba is recorded in the linked list pointed to by usba_root_hubs
*/
int
{
while (hub) {
return (1);
}
}
return (0);
}
/*
* get and store usba_device pointer in the devi
*/
{
/*
* we cannot use parent_data in the usb node because its
* bus parent (eg. PCI nexus driver) uses this data
*
* we cannot use driver data in the other usb nodes since
* usb drivers may need to use this
*/
if (usba_is_root_hub(dip)) {
return (hcdi->hcdi_usba_device);
} else {
return (ddi_get_parent_data(dip));
}
}
/*
* Retrieve the usba_device pointer from the dev without checking for
* the root hub first. This function is only used in polled mode.
*/
{
/*
* Don't call usba_is_root_hub() to find out if this is
* the root hub usba_is_root_hub() calls into the DDI
* where there are locking issues. The dip sent in during
* polled mode will never be the root hub, so just get
* the usba_device pointer from the dip.
*/
return (ddi_get_parent_data(dip));
}
void
{
if (usba_is_root_hub(dip)) {
/* no locking is needed here */
} else {
}
}
/*
* usba_set_node_name() according to class, subclass, and protocol
* following the 1275 USB binding tables.
*/
/* device node table, refer to section 3.2.2.1 of 1275 binding */
};
/* interface-association node table */
"device-wire-adaptor" },
};
/* interface node table, refer to section 3.3.2.1 */
};
/* combined node table, refer to section 3.4.2.1 */
};
sizeof (device_node_name_table)/sizeof (struct node_name_entry);
sizeof (ia_node_name_table)/sizeof (struct node_name_entry);
sizeof (if_node_name_table)/sizeof (struct node_name_entry);
sizeof (combined_node_name_table)/sizeof (struct node_name_entry);
static void
{
int i;
switch (flag) {
/* interface share node names with interface-association */
break;
case FLAG_INTERFACE_NODE:
break;
case FLAG_DEVICE_NODE:
break;
case FLAG_COMBINED_NODE:
break;
default:
return;
}
for (i = 0; i < size; i++) {
break;
}
}
}
#ifdef DEBUG
/*
* walk the children of the parent of this devi and compare the
* name and reg property of each child. If there is a match
* return this node
*/
static dev_info_t *
{
int circular;
"usba_find_existing_node: "
return (NULL);
}
continue;
}
continue;
}
"usba_find_existing_node: "
"usba_find_existing_node: found %s%d (%p)",
"usba_find_existing_node: "
"reg: %x %x %x - %x %x %x",
break;
} else {
}
}
return (child);
}
#endif
/* change all unprintable characters to spaces */
static void
{
while (*instr) {
} else {
*outstr = ' ';
}
outstr++;
instr++;
}
*outstr = '\0';
}
/*
* lookup ugen binding specified in property in
* hcd.conf files
*/
int
{
return (hcdi->hcdi_ugen_default_binding);
}
/*
* driver binding support at device level
*/
{
int rval, i;
int n = 0;
int combined_node = 0;
int is_hub;
char *devprop_str;
"usba_ready_device_node: child=0x%p", (void *)child_dip);
if (address != ROOT_HUB_ADDR) {
0, /* interface index */
0, /* alt interface index */
&if_descr,
if (size != USB_IF_DESCR_SIZE) {
"parsing interface: "
"size (%lu) != USB_IF_DESCR_SIZE (%d)",
return (child_dip);
}
} else {
/* fake an interface descriptor for the root hub */
}
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: property update failed");
return (child_dip);
}
(usb_dev_descr->bDeviceClass == 0)));
/* set node name */
if (combined_node) {
} else {
}
/*
* check force binding rules
*/
(address != usba_ddivs_usbc_xaddress) &&
(!(usba_ddivs_usbc_xhubs && is_hub))) {
force_bind = "ddivs_usbc";
} else if (usba_device->usb_preferred_driver) {
} else if ((address != ROOT_HUB_ADDR) &&
combined_node)) && (!is_hub)) {
force_bind = "ugen";
}
#ifdef DEBUG
/*
* check whether there is another dip with this name and address
* If the dip contains usba_device, it is held by the previous
* round of configuration.
*/
#endif
for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
}
if (force_bind) {
}
/*
* If the callback function of specified driver is registered,
* it will be called here to check whether to take over the device.
*/
"usba_ready_device_node: dev_driver=%s, port =%d,"
"bus =%d, path=%s\n\t",
}
}
/* create compatible names */
if (combined_node) {
/* 1. usbVID,PID.REV */
"usb%x,%x.%x",
/* 2. usbVID,PID */
"usb%x,%x",
if (usb_dev_descr->bDeviceClass != 0) {
/* 3. usbVID,classDC.DSC.DPROTO */
"usb%x,class%x.%x.%x",
/* 4. usbVID,classDC.DSC */
"usb%x,class%x.%x",
/* 5. usbVID,classDC */
"usb%x,class%x",
/* 6. usb,classDC.DSC.DPROTO */
"usb,class%x.%x.%x",
/* 7. usb,classDC.DSC */
"usb,class%x.%x",
/* 8. usb,classDC */
"usb,class%x",
}
if (if_descr.bInterfaceClass != 0) {
/* 9. usbifVID,classIC.ISC.IPROTO */
"usbif%x,class%x.%x.%x",
/* 10. usbifVID,classIC.ISC */
"usbif%x,class%x.%x",
/* 11. usbifVID,classIC */
"usbif%x,class%x",
/* 12. usbif,classIC.ISC.IPROTO */
"usbif,class%x.%x.%x",
/* 13. usbif,classIC.ISC */
"usbif,class%x.%x",
/* 14. usbif,classIC */
"usbif,class%x",
}
/* 15. ugen or usb_mid */
if (usba_get_ugen_binding(child_dip) ==
} else {
}
} else {
if (n_cfgs > 1) {
/* 1. usbVID,PID.REV.configCN */
"usb%x,%x.%x.config%x",
}
/* 2. usbVID,PID.REV */
"usb%x,%x.%x",
/* 3. usbVID,PID.configCN */
if (n_cfgs > 1) {
"usb%x,%x.%x",
}
/* 4. usbVID,PID */
"usb%x,%x",
if (usb_dev_descr->bDeviceClass != 0) {
/* 5. usbVID,classDC.DSC.DPROTO */
"usb%x,class%x.%x.%x",
/* 6. usbVID,classDC.DSC */
"usb%x.class%x.%x",
/* 7. usbVID,classDC */
"usb%x.class%x",
/* 8. usb,classDC.DSC.DPROTO */
"usb,class%x.%x.%x",
/* 9. usb,classDC.DSC */
"usb,class%x.%x",
/* 10. usb,classDC */
"usb,class%x",
}
if (usba_get_ugen_binding(child_dip) ==
/* 11. ugen */
} else {
/* 11. usb,device */
}
}
for (i = 0; i < n; i += 2) {
"compatible name:\t%s\t%s", usba_name[i],
}
"compatible", (char **)usba_name, n);
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: property update failed");
return (child_dip);
}
/* update the address property */
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: address update failed");
}
/* update the usb device properties (PSARC/2000/454) */
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: usb-vendor-id update failed");
}
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: usb-product-id update failed");
}
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: usb-revision-id update failed");
}
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: usb-num-configs update failed");
}
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: usb-release update failed");
}
sizeof (usb_dev_descr_t));
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: usb-descriptor update failed");
}
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: usb-raw-cfg-descriptors update "
"failed");
}
if (usba_device->usb_serialno_str) {
"usb-serialno", devprop_str);
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: "
"usb-serialno update failed");
}
}
if (usba_device->usb_mfg_str) {
"usb-vendor-name", devprop_str);
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: "
"usb-vendor-name update failed");
}
}
if (usba_device->usb_product_str) {
"usb-product-name", devprop_str);
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: "
"usb-product-name update failed");
}
}
if (!combined_node) {
/* update the configuration property */
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: "
"config prop update failed");
}
}
/* create boolean property */
"low-speed");
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: "
"low speed prop update failed");
}
}
/* create boolean property */
"high-speed");
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_device_node: "
"high speed prop update failed");
}
}
"%s%d at port %d: %s, dip=0x%p",
return (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*/
{
int i, n, rval;
/*
* for each interface association, determine all compatible names
*/
"usba_ready_ia_node: "
"port %d, interface = %d, port_status = %x",
/* Parse the interface descriptor */
first_if, /* interface index */
&ia_descr,
*if_count = 1;
if (size != USB_IA_DESCR_SIZE) {
"parsing ia: size (%lu) != USB_IA_DESCR_SIZE (%d)",
return (NULL);
}
/* create reg property */
/* clone this 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;
}
if (rval != DDI_PROP_SUCCESS) {
goto fail;
}
/* check force binding */
if (usba_ugen_force_binding ==
force_bind = "ugen";
}
/*
* check whether there is another dip with this name and address
*/
for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
}
n = 0;
if (force_bind) {
}
/* 1) usbiaVID,PID.REV.configCN.FN */
"usbia%x,%x.%x.config%x.%x",
first_if);
/* 2) usbiaVID,PID.configCN.FN */
"usbia%x,%x.config%x.%x",
first_if);
if (ia_descr.bFunctionClass) {
/* 3) usbiaVID,classFC.FSC.FPROTO */
"usbia%x,class%x.%x.%x",
/* 4) usbiaVID,classFC.FSC */
"usbia%x,class%x.%x",
/* 5) usbiaVID,classFC */
"usbia%x,class%x",
/* 6) usbia,classFC.FSC.FPROTO */
"usbia,class%x.%x.%x",
/* 7) usbia,classFC.FSC */
"usbia,class%x.%x",
/* 8) usbia,classFC */
"usbia,class%x",
}
if (usba_get_ugen_binding(child_dip) ==
/* 9) ugen */
} else {
}
for (i = 0; i < n; i += 2) {
"compatible name:\t%s\t%s", usba_name[i],
}
/* create compatible property */
"compatible", (char **)usba_name, n);
if (rval != DDI_PROP_SUCCESS) {
goto fail;
}
/* update the address property */
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_interface_node: address update failed");
}
/* create property with first interface number */
if (rval != DDI_PROP_SUCCESS) {
goto fail;
}
/* create property with the count of interfaces in this ia */
if (rval != DDI_PROP_SUCCESS) {
goto fail;
}
"%s%d port %d: %s, dip = 0x%p",
return (child_dip);
fail:
return (NULL);
}
/*
* driver binding at interface level, the first arg will be the
* the parent dip
*/
/*ARGSUSED*/
{
int i, n, rval;
/*
* for each interface, determine all compatible names
*/
"usba_ready_interface_node: "
"port %d, interface = %d port status = %x",
/* Parse the interface descriptor */
intf, /* interface index */
0, /* alt interface index */
&if_descr,
if (size != USB_IF_DESCR_SIZE) {
"parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
return (NULL);
}
/* create reg property */
/* clone this dip */
"interface",
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;
}
if (rval != DDI_PROP_SUCCESS) {
goto fail;
}
/* check force binding */
force_bind = "ugen";
}
/*
* check whether there is another dip with this name and address
*/
for (i = 0; i < USBA_MAX_COMPAT_NAMES; i++) {
}
n = 0;
if (force_bind) {
}
/* 1) usbifVID,PID.REV.configCN.IN */
"usbif%x,%x.%x.config%x.%x",
intf);
/* 2) usbifVID,PID.configCN.IN */
"usbif%x,%x.config%x.%x",
intf);
if (if_descr.bInterfaceClass) {
/* 3) usbifVID,classIC.ISC.IPROTO */
"usbif%x,class%x.%x.%x",
/* 4) usbifVID,classIC.ISC */
"usbif%x,class%x.%x",
/* 5) usbifVID,classIC */
"usbif%x,class%x",
/* 6) usbif,classIC.ISC.IPROTO */
"usbif,class%x.%x.%x",
/* 7) usbif,classIC.ISC */
"usbif,class%x.%x",
/* 8) usbif,classIC */
"usbif,class%x",
}
if (usba_get_ugen_binding(child_dip) ==
/* 9) ugen */
}
for (i = 0; i < n; i += 2) {
"compatible name:\t%s\t%s", usba_name[i],
}
/* create compatible property */
"compatible", (char **)usba_name, n);
if (rval != DDI_PROP_SUCCESS) {
goto fail;
}
/* update the address property */
if (rval != DDI_PROP_SUCCESS) {
"usba_ready_interface_node: address update failed");
}
/* create property with if number */
"interface", intf);
if (rval != DDI_PROP_SUCCESS) {
goto fail;
}
"%s%d port %d: %s, dip = 0x%p",
return (child_dip);
fail:
return (NULL);
}
/*
* retrieve string descriptors for manufacturer, vendor and serial
* number
*/
void
{
int l;
"usba_get_usb_string_descr: m=%d, p=%d, s=%d",
/* fetch manufacturer string */
USB_SUCCESS)) {
if (l > 0) {
}
}
/* fetch product string */
tmpbuf, USB_MAXSTRINGLEN) ==
USB_SUCCESS)) {
if (l > 0) {
}
}
/* fetch device serial number string */
USB_SUCCESS)) {
if (l > 0) {
}
}
}
/*
* usba_get_mfg_prod_sn_str:
* Return a string containing mfg, product, serial number strings.
* Remove duplicates if some strings are the same.
*
* Arguments:
* dip - pointer to dev info
* buffer - Where string is returned
* buflen - Length of buffer
*
* Returns:
* Same as second arg.
*/
char *
char *buffer,
int buflen)
{
int return_len = 0;
int len = 0;
buffer[0] = '\0';
/* Manufacturer string exists. */
if ((usba_device->usb_mfg_str) &&
}
/* Product string exists to append. */
if ((usba_device->usb_product_str) &&
if (return_len > 0) {
}
}
/* Serial number string exists to append. */
if ((usba_device->usb_serialno_str) &&
if (return_len > 0) {
}
}
return (buffer);
}
/*
* USB enumeration statistic functions
*/
/*
* Increments the hotplug statistics based on flags.
*/
void
{
if (flags & USBA_TOTAL_HOTPLUG_SUCCESS) {
}
if (flags & USBA_HOTPLUG_SUCCESS) {
}
if (flags & USBA_TOTAL_HOTPLUG_FAILURE) {
}
if (flags & USBA_HOTPLUG_FAILURE) {
}
}
/*
* Retrieve the current enumeration statistics
*/
void
{
}
/*
* Reset the resetable hotplug stats
*/
void
{
hcdi->hcdi_hotplug_success = 0;
hcdi->hcdi_hotplug_failure = 0;
}
/*
* usba_bind_driver():
* This function calls ndi_devi_bind_driver() which tries to
* bind a driver to the device. If the driver binding fails
* we get an rval of NDI_UNBOUD and report an error to the
* syslog that the driver failed binding.
* If rval is something other than NDI_UNBOUND we report an
* error to the console.
*
* This function returns USB_SUCCESS if no errors were
* encountered while binding.
*/
int
{
int rval;
char *name;
/* bind device to the driver */
/* if we fail to bind report an error */
if (name[0] != '\0') {
if (!usb_owns_device(dip)) {
"no driver found for "
"interface %d (nodename: '%s') of %s",
} else {
"no driver found for device %s", name);
}
} else {
"no driver found for device %s", name);
}
return (USB_FAILURE);
}
}
/*
* usba_get_hc_dma_attr:
* function returning dma attributes of the HCD
*
* Arguments:
* dip - pointer to devinfo of the client
*
* Return Values:
* hcdi_dma_attr
*/
{
return (hcdi->hcdi_dma_attr);
}
/*
* usba_check_for_leaks:
* check usba_device structure for leaks
*
* Arguments:
* usba_device - usba_device structure pointer
*/
void
{
int leaks = 0;
"usba_check_for_leaks: %s%d usba_device=0x%p",
/*
* default pipe is still open
* all other pipes should be closed
*/
&usba_device->usb_ph_list[i];
if (ph_impl->usba_ph_data) {
"%s%d: leaking pipehandle=0x%p (0x%p) ep_addr=0x%x",
(void *)ph_impl,
(void *)ph_impl->usba_ph_data,
ph_open_cnt++;
leaks++;
#ifndef DEBUG
#endif
}
}
usb_allocated, "request wrappers");
ASSERT(ph_open_cnt == 0);
ASSERT(req_wrp_leaks == 0);
if (req_wrp_leaks) {
while ((entry = usba_rm_first_from_list(
leaks++;
"%s%d: leaking request 0x%p",
/*
* put it back, usba_req_wrapper_free
* expects it on the list
*/
&wrp->wr_allocated_list);
}
}
"usba_check_for_leaks: if=%d client_flags=0x%x",
while (entry) {
if (!i_ddi_devi_attached(dip)) {
"%s%d: leaking dev_data 0x%p",
(void *)dev_data);
leaks++;
}
}
}
"%s%d: did no usb_client_detach",
leaks++;
}
dip;
"%s%d: did no usb_unregister_event_cbs",
leaks++;
}
}
if (leaks) {
"all %d leaks fixed", leaks);
}
}