17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5cbab2b26Slg * Common Development and Distribution License (the "License").
6cbab2b26Slg * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
20cbab2b26Slg */
21cbab2b26Slg /*
22ff0e937bSRaymond Chen * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
24e2c88f0cSGarrett D'Amore *
25e2c88f0cSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org>
26*0d2006e4SRobert Mustacchi * Copyright 2019, Joyent, Inc.
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support
317c478bd9Sstevel@tonic-gate *
327c478bd9Sstevel@tonic-gate * This module builds a tree of parsed USB standard descriptors and unparsed
337c478bd9Sstevel@tonic-gate * Class/Vendor specific (C/V) descriptors. Routines are grouped into three
347c478bd9Sstevel@tonic-gate * groups: those which build the tree, those which take it down, and those which
357c478bd9Sstevel@tonic-gate * dump it.
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * The tree built hangs off of the dev_cfg field of the usb_client_dev_data_t
387c478bd9Sstevel@tonic-gate * structure returned by usb_get_dev_data(). The tree consists of different
397c478bd9Sstevel@tonic-gate * kinds of tree nodes (usb_xxx_data_t) each containing a standard USB
407c478bd9Sstevel@tonic-gate * descriptor (usb_xxx_descr_t) and pointers to arrays of other nodes.
417c478bd9Sstevel@tonic-gate *
427c478bd9Sstevel@tonic-gate * Arrays are dynamically sized, as the descriptors coming from the device may
437c478bd9Sstevel@tonic-gate * lie, but the number of descriptors from the device is a more reliable
447c478bd9Sstevel@tonic-gate * indicator of configuration. This makes the code more robust. After the raw
457c478bd9Sstevel@tonic-gate * descriptor data has been parsed into a non-sparse tree, the tree is ordered
467c478bd9Sstevel@tonic-gate * and made sparse with a bin-sort style algorithm.
477c478bd9Sstevel@tonic-gate *
487c478bd9Sstevel@tonic-gate * dev_cfg is an array of configuration tree nodes. Each contains space for one
497c478bd9Sstevel@tonic-gate * parsed standard USB configuration descriptor, a pointer to an array of c/v
507c478bd9Sstevel@tonic-gate * tree nodes and a pointer to an array of interface tree nodes.
517c478bd9Sstevel@tonic-gate *
527c478bd9Sstevel@tonic-gate * Each interface tree node represents a group of interface descriptors, called
537c478bd9Sstevel@tonic-gate * alternates, with the same interface number. Thus, each interface tree node
547c478bd9Sstevel@tonic-gate * has a pointer to an array of alternate-interface tree nodes each containing a
557c478bd9Sstevel@tonic-gate * standard USB interface descriptor. Alternate-interface tree nodes also
567c478bd9Sstevel@tonic-gate * contain a pointer to an array of c/v tree nodes and a pointer to an array of
577c478bd9Sstevel@tonic-gate * endpoint tree nodes.
587c478bd9Sstevel@tonic-gate *
597c478bd9Sstevel@tonic-gate * Endpoint tree nodes contain a standard endpoint descriptor, plus a pointer to
607c478bd9Sstevel@tonic-gate * an array of c/v tree nodes.
617c478bd9Sstevel@tonic-gate *
627c478bd9Sstevel@tonic-gate * Each array in the tree contains elements ranging from 0 to the largest key
637c478bd9Sstevel@tonic-gate * value of it's elements. Endpoints are a special case. The direction bit is
647c478bd9Sstevel@tonic-gate * right shifted over three unused bits before the index is determined, leaving
657c478bd9Sstevel@tonic-gate * a range of 0..31 instead of a sparsely-populated range of 0..255.
667c478bd9Sstevel@tonic-gate *
677c478bd9Sstevel@tonic-gate * The indices of tree elements coincide with their USB key values. For
687c478bd9Sstevel@tonic-gate * example, standard USB devices have no configuration 0; if they have one
697c478bd9Sstevel@tonic-gate * configuration it is #1. dev_cfg[0] is zeroed out; dev_cfg[1] is the root
707c478bd9Sstevel@tonic-gate * of configuration #1.
717c478bd9Sstevel@tonic-gate *
727c478bd9Sstevel@tonic-gate * The idea here is for a driver to be able to parse the tree to easily find a
737c478bd9Sstevel@tonic-gate * desired descriptor. For example, the interval of endpoint 2, alternate 3,
747c478bd9Sstevel@tonic-gate * interface 1, configuration 1 would be:
757c478bd9Sstevel@tonic-gate * dv->dev_cfg[1].cfg_if[1].if_alt[3].altif_ep[2].ep_descr.bInterval
767c478bd9Sstevel@tonic-gate *
777c478bd9Sstevel@tonic-gate * How the tree is built:
787c478bd9Sstevel@tonic-gate *
797c478bd9Sstevel@tonic-gate * usb_build_descr_tree() is responsible for the whole process.
807c478bd9Sstevel@tonic-gate *
817c478bd9Sstevel@tonic-gate * Next, usba_build_descr_tree() coordinates parsing this byte stream,
827c478bd9Sstevel@tonic-gate * descriptor by descriptor. usba_build_descr_tree() calls the appropriate
837c478bd9Sstevel@tonic-gate * usba_process_xx_descr() function to interpret and install each descriptor in
847c478bd9Sstevel@tonic-gate * the tree, based on the descriptor's type. When done with this phase, a
857c478bd9Sstevel@tonic-gate * non-sparse tree exists containing tree nodes with descriptors in the order
867c478bd9Sstevel@tonic-gate * they were found in the raw data.
877c478bd9Sstevel@tonic-gate *
887c478bd9Sstevel@tonic-gate * All levels of the tree, except alternates, remain non-sparse. Alternates are
897c478bd9Sstevel@tonic-gate * moved, possibly, within their array, so that descriptors are indexed by their
907c478bd9Sstevel@tonic-gate * alternate ID.
917c478bd9Sstevel@tonic-gate *
927c478bd9Sstevel@tonic-gate * The usba_reg_state_t structure maintains state of the tree-building process,
937c478bd9Sstevel@tonic-gate * helping coordinate all routines involved.
947c478bd9Sstevel@tonic-gate */
957c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK
967c478bd9Sstevel@tonic-gate #include <sys/usb/usba.h>
977c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
987c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_private.h>
997c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
1007c478bd9Sstevel@tonic-gate #include <sys/usb/hubd/hub.h>
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usbai_register_impl.h>
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate * Header needed for use by this module only.
1067c478bd9Sstevel@tonic-gate * However, function may be used in V0.8 drivers so needs to be global.
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate int usb_log_descr_tree(usb_client_dev_data_t *, usb_log_handle_t,
1097c478bd9Sstevel@tonic-gate uint_t, uint_t);
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate /* Debug stuff */
1127c478bd9Sstevel@tonic-gate usb_log_handle_t usbai_reg_log_handle;
1134610e4a0Sfrits uint_t usbai_register_errlevel = USB_LOG_L2;
1144610e4a0Sfrits uint_t usbai_register_dump_errlevel = USB_LOG_L2;
1154610e4a0Sfrits uint_t usbai_register_errmask = (uint_t)-1;
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate /* Function prototypes */
1187c478bd9Sstevel@tonic-gate static int usba_build_descr_tree(dev_info_t *, usba_device_t *,
1197c478bd9Sstevel@tonic-gate usb_client_dev_data_t *);
1207c478bd9Sstevel@tonic-gate static void usba_process_cfg_descr(usba_reg_state_t *);
1217c478bd9Sstevel@tonic-gate static int usba_process_if_descr(usba_reg_state_t *, boolean_t *);
1227c478bd9Sstevel@tonic-gate static int usba_process_ep_descr(usba_reg_state_t *);
123993e3fafSRobert Mustacchi static int usba_process_ss_ep_comp_descr(usba_reg_state_t *);
1247c478bd9Sstevel@tonic-gate static int usba_process_cv_descr(usba_reg_state_t *);
1257c478bd9Sstevel@tonic-gate static int usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device,
1267c478bd9Sstevel@tonic-gate usba_reg_state_t *state);
1277c478bd9Sstevel@tonic-gate static void* usba_kmem_realloc(void *, int, int);
1287c478bd9Sstevel@tonic-gate static void usba_augment_array(void **, uint_t, uint_t);
1297c478bd9Sstevel@tonic-gate static void usba_make_alts_sparse(usb_alt_if_data_t **, uint_t *);
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate static void usba_order_tree(usba_reg_state_t *);
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate static void usba_free_if_array(usb_if_data_t *, uint_t);
1347c478bd9Sstevel@tonic-gate static void usba_free_ep_array(usb_ep_data_t *, uint_t);
1357c478bd9Sstevel@tonic-gate static void usba_free_cv_array(usb_cvs_data_t *, uint_t);
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate static int usba_dump_descr_tree(dev_info_t *, usb_client_dev_data_t *,
1387c478bd9Sstevel@tonic-gate usb_log_handle_t, uint_t, uint_t);
1397c478bd9Sstevel@tonic-gate static void usba_dump_if(usb_if_data_t *, usb_log_handle_t,
1407c478bd9Sstevel@tonic-gate uint_t, uint_t, char *);
1417c478bd9Sstevel@tonic-gate static void usba_dump_ep(uint_t, usb_ep_data_t *, usb_log_handle_t, uint_t,
1427c478bd9Sstevel@tonic-gate uint_t, char *);
1437c478bd9Sstevel@tonic-gate static void usba_dump_cv(usb_cvs_data_t *, usb_log_handle_t, uint_t, uint_t,
1447c478bd9Sstevel@tonic-gate char *, int);
1457c478bd9Sstevel@tonic-gate static void usba_dump_bin(uint8_t *, int, int, usb_log_handle_t,
1467c478bd9Sstevel@tonic-gate uint_t, uint_t, char *, int);
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate /* Framework initialization. */
1497c478bd9Sstevel@tonic-gate void
usba_usbai_register_initialization()1507c478bd9Sstevel@tonic-gate usba_usbai_register_initialization()
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate usbai_reg_log_handle = usb_alloc_log_hdl(NULL, "usbreg",
153112116d8Sfb &usbai_register_errlevel,
154112116d8Sfb &usbai_register_errmask, NULL,
155112116d8Sfb 0);
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
158112116d8Sfb "usba_usbai_register_initialization");
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /* Framework destruction. */
1637c478bd9Sstevel@tonic-gate void
usba_usbai_register_destroy()1647c478bd9Sstevel@tonic-gate usba_usbai_register_destroy()
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1677c478bd9Sstevel@tonic-gate "usba_usbai_register destroy");
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate usb_free_log_hdl(usbai_reg_log_handle);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate * usb_client_attach:
1757c478bd9Sstevel@tonic-gate *
1767c478bd9Sstevel@tonic-gate * Arguments:
1777c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client
1787c478bd9Sstevel@tonic-gate * version - USBA registration version number
1797c478bd9Sstevel@tonic-gate * flags - None used
1807c478bd9Sstevel@tonic-gate *
1817c478bd9Sstevel@tonic-gate * Return Values:
1827c478bd9Sstevel@tonic-gate * USB_SUCCESS - attach succeeded
1837c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - received null dip
1847c478bd9Sstevel@tonic-gate * USB_INVALID_VERSION - version argument is incorrect.
1857c478bd9Sstevel@tonic-gate * USB_FAILURE - other internal failure
1867c478bd9Sstevel@tonic-gate */
1877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1887c478bd9Sstevel@tonic-gate int
usb_client_attach(dev_info_t * dip,uint_t version,usb_flags_t flags)1897c478bd9Sstevel@tonic-gate usb_client_attach(dev_info_t *dip, uint_t version, usb_flags_t flags)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate int rval;
1927c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate if (dip == NULL) {
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2007c478bd9Sstevel@tonic-gate "usb_client attach:");
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate /*
2057c478bd9Sstevel@tonic-gate * Allow exact match for legacy (DDK 0.8/9) drivers, or same major
2067c478bd9Sstevel@tonic-gate * VERSion and smaller or same minor version for non-legacy drivers.
2077c478bd9Sstevel@tonic-gate */
2087c478bd9Sstevel@tonic-gate if ((version !=
2097c478bd9Sstevel@tonic-gate USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) &&
2107c478bd9Sstevel@tonic-gate ((USBA_GET_MAJOR(version) != USBA_MAJOR_VER) ||
2117c478bd9Sstevel@tonic-gate (USBA_GET_MINOR(version) > USBA_MINOR_VER))) {
2127c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2137c478bd9Sstevel@tonic-gate "Incorrect USB driver version for %s%d: found: %d.%d, "
2147c478bd9Sstevel@tonic-gate "expecting %d.%d",
2157c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip),
2167c478bd9Sstevel@tonic-gate USBA_GET_MAJOR(version), USBA_GET_MINOR(version),
2177c478bd9Sstevel@tonic-gate USBA_MAJOR_VER, USBA_MINOR_VER);
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate if (version == USBA_MAKE_VER(USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER)) {
223d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2247c478bd9Sstevel@tonic-gate "Accepting legacy USB driver version %d.%d for %s%d",
2257c478bd9Sstevel@tonic-gate USBA_LEG_MAJOR_VER, USBA_LEG_MINOR_VER,
2267c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip));
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-major",
230112116d8Sfb USBA_GET_MAJOR(version));
2317c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate return (USB_FAILURE);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate rval = ndi_prop_update_int(DDI_DEV_T_NONE, dip, "driver-minor",
236112116d8Sfb USBA_GET_MINOR(version));
2377c478bd9Sstevel@tonic-gate if (rval != DDI_PROP_SUCCESS) {
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate return (USB_FAILURE);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
2437c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) {
2447c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |=
245112116d8Sfb USBA_CLIENT_FLAG_ATTACH;
2467c478bd9Sstevel@tonic-gate usba_device->usb_client_attach_list->dip = dip;
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2517c478bd9Sstevel@tonic-gate "usb_client attach: done");
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate * usb_client_detach:
2597c478bd9Sstevel@tonic-gate * free dev_data is reg != NULL, not much else to do
2607c478bd9Sstevel@tonic-gate *
2617c478bd9Sstevel@tonic-gate * Arguments:
2627c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client
2637c478bd9Sstevel@tonic-gate * reg - return registration data at this address
2647c478bd9Sstevel@tonic-gate */
2657c478bd9Sstevel@tonic-gate void
usb_client_detach(dev_info_t * dip,usb_client_dev_data_t * reg)2667c478bd9Sstevel@tonic-gate usb_client_detach(dev_info_t *dip, usb_client_dev_data_t *reg)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2717c478bd9Sstevel@tonic-gate "usb_client_detach:");
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate if (dip) {
2747c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2757c478bd9Sstevel@tonic-gate "Unregistering usb client %s%d: reg=0x%p",
276112116d8Sfb ddi_driver_name(dip), ddi_get_instance(dip), (void *)reg);
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate usb_free_dev_data(dip, reg);
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
2817c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(dip), "usb_mid") != 0) {
2827c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] &=
283112116d8Sfb ~USBA_CLIENT_FLAG_ATTACH;
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
2897c478bd9Sstevel@tonic-gate "usb_client_detach done");
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate * usb_register_client (deprecated):
2957c478bd9Sstevel@tonic-gate * The client registers with USBA during attach.
2967c478bd9Sstevel@tonic-gate */
2977c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2987c478bd9Sstevel@tonic-gate int
usb_register_client(dev_info_t * dip,uint_t version,usb_client_dev_data_t ** reg,usb_reg_parse_lvl_t parse_level,usb_flags_t flags)2997c478bd9Sstevel@tonic-gate usb_register_client(dev_info_t *dip, uint_t version,
3007c478bd9Sstevel@tonic-gate usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level,
3017c478bd9Sstevel@tonic-gate usb_flags_t flags)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate int rval = usb_client_attach(dip, version, flags);
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) {
3067c478bd9Sstevel@tonic-gate rval = usb_get_dev_data(dip, reg, parse_level, flags);
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate if (rval != USB_SUCCESS) {
3097c478bd9Sstevel@tonic-gate usb_client_detach(dip, NULL);
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate return (rval);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate * usb_unregister_client (deprecated):
3197c478bd9Sstevel@tonic-gate * Undo the makings of usb_get_dev_data(). Free memory if allocated.
3207c478bd9Sstevel@tonic-gate *
3217c478bd9Sstevel@tonic-gate * Arguments:
3227c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client
3237c478bd9Sstevel@tonic-gate * reg - pointer to registration data to be freed
3247c478bd9Sstevel@tonic-gate */
3257c478bd9Sstevel@tonic-gate void
usb_unregister_client(dev_info_t * dip,usb_client_dev_data_t * reg)3267c478bd9Sstevel@tonic-gate usb_unregister_client(dev_info_t *dip, usb_client_dev_data_t *reg)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate usb_client_detach(dip, reg);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * usb_get_dev_data:
3347c478bd9Sstevel@tonic-gate * On completion, the registration data has been initialized.
3357c478bd9Sstevel@tonic-gate * Most data items are straightforward.
3367c478bd9Sstevel@tonic-gate * Among the items returned in the data is the tree of
3377c478bd9Sstevel@tonic-gate * parsed descriptors, in dev_cfg; the number of configurations parsed,
3387c478bd9Sstevel@tonic-gate * in dev_n_cfg; a pointer to the current configuration in the tree,
3397c478bd9Sstevel@tonic-gate * in dev_curr_cfg; the index of the first valid interface in the
3407c478bd9Sstevel@tonic-gate * tree, in dev_curr_if, and a parse level that accurately reflects what
3417c478bd9Sstevel@tonic-gate * is in the tree, in dev_parse_level.
3427c478bd9Sstevel@tonic-gate *
3437c478bd9Sstevel@tonic-gate * This routine sets up directly-initialized fields, and calls
3447c478bd9Sstevel@tonic-gate * usb_build_descr_tree() to parse the raw descriptors and initialize the
3457c478bd9Sstevel@tonic-gate * tree.
3467c478bd9Sstevel@tonic-gate *
3477c478bd9Sstevel@tonic-gate * Parse_level determines the extent to which the tree is built. It has
3487c478bd9Sstevel@tonic-gate * the following values:
3497c478bd9Sstevel@tonic-gate *
3507c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_NONE - Build no tree. dev_n_cfg will return 0, dev_cfg
3517c478bd9Sstevel@tonic-gate * and dev_curr_cfg will return NULL.
3527c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_IF - Parse configured interface only, if configuration#
3537c478bd9Sstevel@tonic-gate * and interface properties are set (as when different
3547c478bd9Sstevel@tonic-gate * interfaces are viewed by the OS as different device
3557c478bd9Sstevel@tonic-gate * instances). If an OS device instance is set up to
3567c478bd9Sstevel@tonic-gate * represent an entire physical device, this works
3577c478bd9Sstevel@tonic-gate * like USB_PARSE_LVL_ALL.
3587c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_CFG - Parse entire configuration of configured interface
3597c478bd9Sstevel@tonic-gate * only. This is like USB_PARSE_LVL_IF except entire
3607c478bd9Sstevel@tonic-gate * configuration is returned.
3617c478bd9Sstevel@tonic-gate * USB_PARSE_LVL_ALL - Parse entire device (all configurations), even
3627c478bd9Sstevel@tonic-gate * when driver is bound to a single interface of a
3637c478bd9Sstevel@tonic-gate * single configuration.
3647c478bd9Sstevel@tonic-gate *
3657c478bd9Sstevel@tonic-gate * No tree is built for root hubs, regardless of parse_level.
3667c478bd9Sstevel@tonic-gate *
3677c478bd9Sstevel@tonic-gate * Arguments:
3687c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client
3697c478bd9Sstevel@tonic-gate * version - USBA registration version number
3707c478bd9Sstevel@tonic-gate * reg - return registration data at this address
3717c478bd9Sstevel@tonic-gate * parse_level - See above
3727c478bd9Sstevel@tonic-gate * flags - None used
3737c478bd9Sstevel@tonic-gate *
3747c478bd9Sstevel@tonic-gate * Return Values:
3757c478bd9Sstevel@tonic-gate * USB_SUCCESS - usb_get_dev_data succeeded
3767c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - received null dip or reg argument
3777c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context
3787c478bd9Sstevel@tonic-gate * USB_FAILURE - bad descriptor info or other internal failure
3797c478bd9Sstevel@tonic-gate *
3807c478bd9Sstevel@tonic-gate * Note: The non-standard USB descriptors are returned in RAW format.
3817c478bd9Sstevel@tonic-gate * returns initialized registration data. Most data items are clear.
3827c478bd9Sstevel@tonic-gate * Among the items returned is the tree of parsed descriptors in dev_cfg;
3837c478bd9Sstevel@tonic-gate * and the number of configurations parsed in dev_n_cfg.
3847c478bd9Sstevel@tonic-gate *
3857c478bd9Sstevel@tonic-gate * The registration data is not shared. each client receives its own
3867c478bd9Sstevel@tonic-gate * copy.
3877c478bd9Sstevel@tonic-gate */
3887c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3897c478bd9Sstevel@tonic-gate int
usb_get_dev_data(dev_info_t * dip,usb_client_dev_data_t ** reg,usb_reg_parse_lvl_t parse_level,usb_flags_t flags)3907c478bd9Sstevel@tonic-gate usb_get_dev_data(dev_info_t *dip,
3917c478bd9Sstevel@tonic-gate usb_client_dev_data_t **reg, usb_reg_parse_lvl_t parse_level,
3927c478bd9Sstevel@tonic-gate usb_flags_t flags)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate usb_client_dev_data_t *usb_reg = NULL;
3957c478bd9Sstevel@tonic-gate char *tmpbuf = NULL;
3967c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
3977c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS;
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if ((dip == NULL) || (reg == NULL)) {
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
4057c478bd9Sstevel@tonic-gate "usb_get_dev_data: %s%d",
4067c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip));
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate *reg = NULL;
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate /* did the client attach first? */
4117c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4127c478bd9Sstevel@tonic-gate "driver-major", -1) == -1) {
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
4177c478bd9Sstevel@tonic-gate "driver-minor", -1) == -1) {
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate return (USB_INVALID_VERSION);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate usb_reg = kmem_zalloc(sizeof (usb_client_dev_data_t), KM_SLEEP);
4237c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
4247c478bd9Sstevel@tonic-gate usb_reg->dev_descr = usba_device->usb_dev_descr;
4257c478bd9Sstevel@tonic-gate usb_reg->dev_default_ph = usba_get_dflt_pipe_handle(dip);
4267c478bd9Sstevel@tonic-gate if (usb_reg->dev_default_ph == NULL) {
4277c478bd9Sstevel@tonic-gate kmem_free(usb_reg, sizeof (usb_client_dev_data_t));
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate return (USB_FAILURE);
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate usb_reg->dev_iblock_cookie = usba_hcdi_get_hcdi(
4337c478bd9Sstevel@tonic-gate usba_device->usb_root_hub_dip)->hcdi_soft_iblock_cookie;
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
436112116d8Sfb "cookie = 0x%p", (void *)usb_reg->dev_iblock_cookie);
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate tmpbuf = (char *)kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate if (usba_device->usb_mfg_str != NULL) {
4417c478bd9Sstevel@tonic-gate usb_reg->dev_mfg = kmem_zalloc(
442112116d8Sfb strlen(usba_device->usb_mfg_str) + 1, KM_SLEEP);
4437c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_mfg, usba_device->usb_mfg_str);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate if (usba_device->usb_product_str != NULL) {
4477c478bd9Sstevel@tonic-gate usb_reg->dev_product = kmem_zalloc(
448112116d8Sfb strlen(usba_device->usb_product_str) + 1,
449112116d8Sfb KM_SLEEP);
4507c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_product,
451112116d8Sfb usba_device->usb_product_str);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate if (usba_device->usb_serialno_str != NULL) {
4557c478bd9Sstevel@tonic-gate usb_reg->dev_serial = kmem_zalloc(
456112116d8Sfb strlen(usba_device->usb_serialno_str) + 1,
457112116d8Sfb KM_SLEEP);
4587c478bd9Sstevel@tonic-gate (void) strcpy(usb_reg->dev_serial,
459112116d8Sfb usba_device->usb_serialno_str);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate if ((usb_reg->dev_parse_level = parse_level) == USB_PARSE_LVL_NONE) {
4637c478bd9Sstevel@tonic-gate rval = USB_SUCCESS;
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate } else if ((rval = usba_build_descr_tree(dip, usba_device, usb_reg)) !=
4667c478bd9Sstevel@tonic-gate USB_SUCCESS) {
4677c478bd9Sstevel@tonic-gate usb_unregister_client(dip, usb_reg);
4687c478bd9Sstevel@tonic-gate usb_reg = NULL;
4697c478bd9Sstevel@tonic-gate } else {
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate /* Current tree cfg is always zero if only one cfg in tree. */
4727c478bd9Sstevel@tonic-gate if (usb_reg->dev_n_cfg == 1) {
4737c478bd9Sstevel@tonic-gate usb_reg->dev_curr_cfg = &usb_reg->dev_cfg[0];
4747c478bd9Sstevel@tonic-gate } else {
4757c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
4767c478bd9Sstevel@tonic-gate usb_reg->dev_curr_cfg =
4777c478bd9Sstevel@tonic-gate &usb_reg->dev_cfg[usba_device->usb_active_cfg_ndx];
4787c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
4797c478bd9Sstevel@tonic-gate ASSERT(usb_reg->dev_curr_cfg != NULL);
4807c478bd9Sstevel@tonic-gate ASSERT(usb_reg->dev_curr_cfg->cfg_descr.bLength ==
4817c478bd9Sstevel@tonic-gate USB_CFG_DESCR_SIZE);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate * Keep dev_curr_if at device's single interface only if that
4867c478bd9Sstevel@tonic-gate * particular interface has been explicitly defined by the
4877c478bd9Sstevel@tonic-gate * device.
4887c478bd9Sstevel@tonic-gate */
4897c478bd9Sstevel@tonic-gate usb_reg->dev_curr_if = usba_get_ifno(dip);
4907c478bd9Sstevel@tonic-gate #ifdef DEBUG
4917c478bd9Sstevel@tonic-gate (void) usb_log_descr_tree(usb_reg, usbai_reg_log_handle,
492112116d8Sfb usbai_register_dump_errlevel, (uint_t)-1);
4937c478bd9Sstevel@tonic-gate #endif
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate * Fail if interface and configuration of dev_curr_if and
4967c478bd9Sstevel@tonic-gate * dev_curr_cfg don't exist or are invalid. (Shouldn't happen.)
4977c478bd9Sstevel@tonic-gate * These indices must be reliable for tree traversal.
4987c478bd9Sstevel@tonic-gate */
4997c478bd9Sstevel@tonic-gate if ((usb_reg->dev_curr_cfg->cfg_n_if <= usb_reg->dev_curr_if) ||
5007c478bd9Sstevel@tonic-gate (usb_reg->dev_curr_cfg->cfg_descr.bLength == 0) ||
5017c478bd9Sstevel@tonic-gate (usb_reg->dev_curr_cfg->cfg_if[usb_reg->dev_curr_if].
5027c478bd9Sstevel@tonic-gate if_n_alt == 0)) {
5037c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle,
5047c478bd9Sstevel@tonic-gate "usb_get_dev_data: dev_curr_cfg or "
5057c478bd9Sstevel@tonic-gate "dev_curr_if have no descriptors");
5067c478bd9Sstevel@tonic-gate usb_unregister_client(dip, usb_reg);
5077c478bd9Sstevel@tonic-gate usb_reg = NULL;
5087c478bd9Sstevel@tonic-gate rval = USB_FAILURE;
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate *reg = usb_reg;
5137c478bd9Sstevel@tonic-gate kmem_free(tmpbuf, USB_MAXSTRINGLEN);
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate if (rval == USB_SUCCESS) {
5167c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *entry = kmem_zalloc(
517112116d8Sfb sizeof (*entry), KM_SLEEP);
5187c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |=
521112116d8Sfb USBA_CLIENT_FLAG_DEV_DATA;
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate entry->cddl_dip = dip;
5247c478bd9Sstevel@tonic-gate entry->cddl_dev_data = usb_reg;
5257c478bd9Sstevel@tonic-gate entry->cddl_ifno = usba_get_ifno(dip);
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate entry->cddl_next =
528112116d8Sfb usba_device->usb_client_dev_data_list.cddl_next;
5297c478bd9Sstevel@tonic-gate if (entry->cddl_next) {
5307c478bd9Sstevel@tonic-gate entry->cddl_next->cddl_prev = entry;
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate entry->cddl_prev = &usba_device->usb_client_dev_data_list;
5337c478bd9Sstevel@tonic-gate usba_device->usb_client_dev_data_list.cddl_next = entry;
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
5397c478bd9Sstevel@tonic-gate "usb_get_dev_data rval=%d", rval);
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate return (rval);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate * usb_free_dev_data
5477c478bd9Sstevel@tonic-gate * undoes what usb_get_dev_data does
5487c478bd9Sstevel@tonic-gate *
5497c478bd9Sstevel@tonic-gate * Arguments:
5507c478bd9Sstevel@tonic-gate * dip - pointer to devinfo node of the client
5517c478bd9Sstevel@tonic-gate * reg - return registration data at this address
5527c478bd9Sstevel@tonic-gate */
5537c478bd9Sstevel@tonic-gate void
usb_free_dev_data(dev_info_t * dip,usb_client_dev_data_t * reg)5547c478bd9Sstevel@tonic-gate usb_free_dev_data(dev_info_t *dip, usb_client_dev_data_t *reg)
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate if (dip == NULL) {
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate return;
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
5627c478bd9Sstevel@tonic-gate "usb_free_dev_data %s%d: reg=0x%p",
563112116d8Sfb ddi_driver_name(dip), ddi_get_instance(dip), (void *)reg);
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate if (reg != NULL) {
5667c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
5677c478bd9Sstevel@tonic-gate usb_client_dev_data_list_t *next, *prev, *entry;
5687c478bd9Sstevel@tonic-gate int matches = 0;
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate if (reg->dev_serial != NULL) {
5717c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_serial,
5727c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_serial) + 1);
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate if (reg->dev_product != NULL) {
5767c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_product,
5777c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_product) + 1);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate if (reg->dev_mfg != NULL) {
5817c478bd9Sstevel@tonic-gate kmem_free((char *)reg->dev_mfg,
5827c478bd9Sstevel@tonic-gate strlen((char *)reg->dev_mfg) + 1);
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate /* Free config tree under reg->dev_cfg. */
5867c478bd9Sstevel@tonic-gate if (reg->dev_cfg != NULL) {
5877c478bd9Sstevel@tonic-gate usb_free_descr_tree(dip, reg);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
5917c478bd9Sstevel@tonic-gate prev = &usba_device->usb_client_dev_data_list;
5927c478bd9Sstevel@tonic-gate entry = usba_device->usb_client_dev_data_list.cddl_next;
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate /* free the entries in usb_client_data_list */
5957c478bd9Sstevel@tonic-gate while (entry) {
5967c478bd9Sstevel@tonic-gate next = entry->cddl_next;
5977c478bd9Sstevel@tonic-gate if ((dip == entry->cddl_dip) &&
5987c478bd9Sstevel@tonic-gate (reg == entry->cddl_dev_data)) {
5997c478bd9Sstevel@tonic-gate prev->cddl_next = entry->cddl_next;
6007c478bd9Sstevel@tonic-gate if (entry->cddl_next) {
6017c478bd9Sstevel@tonic-gate entry->cddl_next->cddl_prev = prev;
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate kmem_free(entry, sizeof (*entry));
6047c478bd9Sstevel@tonic-gate } else {
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate * any other entries for this interface?
6077c478bd9Sstevel@tonic-gate */
6087c478bd9Sstevel@tonic-gate if (usba_get_ifno(dip) == entry->cddl_ifno) {
6097c478bd9Sstevel@tonic-gate matches++;
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate prev = entry;
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate entry = next;
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_REGISTER,
6177c478bd9Sstevel@tonic-gate usbai_reg_log_handle,
6187c478bd9Sstevel@tonic-gate "usb_free_dev_data: next=0x%p flags[%d]=0x%x",
619112116d8Sfb (void *)usba_device->usb_client_dev_data_list.cddl_next,
6207c478bd9Sstevel@tonic-gate usba_get_ifno(dip),
6217c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)]);
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate if (matches == 0) {
6247c478bd9Sstevel@tonic-gate usba_device->
6257c478bd9Sstevel@tonic-gate usb_client_flags[usba_get_ifno(dip)] &=
626112116d8Sfb ~USBA_CLIENT_FLAG_DEV_DATA;
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate kmem_free(reg, sizeof (usb_client_dev_data_t));
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
6347c478bd9Sstevel@tonic-gate "usb_free_dev_data done");
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate /*
6387c478bd9Sstevel@tonic-gate * usba_build_descr_tree:
6397c478bd9Sstevel@tonic-gate * This builds the descriptor tree. See module header comment for tree
6407c478bd9Sstevel@tonic-gate * description.
6417c478bd9Sstevel@tonic-gate *
6427c478bd9Sstevel@tonic-gate * Arguments:
6437c478bd9Sstevel@tonic-gate * dip - devinfo pointer - cannot be NULL.
6447c478bd9Sstevel@tonic-gate * usba_device - pointer to usba_device structure.
6457c478bd9Sstevel@tonic-gate * usb_reg - pointer to area returned to client describing device.
6467c478bd9Sstevel@tonic-gate * number of configuration (dev_n_cfg) and array of
6477c478bd9Sstevel@tonic-gate * configurations (dev_cfg) are initialized here -
6487c478bd9Sstevel@tonic-gate * dev_parse_level used and may be modified to fit
6497c478bd9Sstevel@tonic-gate * current configuration.
6507c478bd9Sstevel@tonic-gate * Return values:
6517c478bd9Sstevel@tonic-gate * USB_SUCCESS - Tree build succeeded
6527c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - dev_parse_level in usb_reg is invalid.
6537c478bd9Sstevel@tonic-gate * USB_FAILURE - Bad descriptor info or other internal failure
6547c478bd9Sstevel@tonic-gate */
6557c478bd9Sstevel@tonic-gate static int
usba_build_descr_tree(dev_info_t * dip,usba_device_t * usba_device,usb_client_dev_data_t * usb_reg)6567c478bd9Sstevel@tonic-gate usba_build_descr_tree(dev_info_t *dip, usba_device_t *usba_device,
6577c478bd9Sstevel@tonic-gate usb_client_dev_data_t *usb_reg)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate usba_reg_state_t state; /* State of tree construction */
6607c478bd9Sstevel@tonic-gate int cfg_len_so_far = 0; /* Bytes found, this config. */
6617c478bd9Sstevel@tonic-gate uint8_t *last_byte; /* Ptr to the end of the cfg cloud. */
6627c478bd9Sstevel@tonic-gate uint_t this_cfg_ndx; /* Configuration counter. */
6637c478bd9Sstevel@tonic-gate uint_t high_cfg_bound; /* High config index + 1. */
6647c478bd9Sstevel@tonic-gate uint_t low_cfg_bound; /* Low config index. */
6657c478bd9Sstevel@tonic-gate boolean_t process_this_if_tree = B_FALSE; /* Save alts, eps, */
6667c478bd9Sstevel@tonic-gate /* of this interface. */
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
6697c478bd9Sstevel@tonic-gate "usba_build_descr_tree starting");
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate bzero(&state, sizeof (usba_reg_state_t));
6727c478bd9Sstevel@tonic-gate state.dip = dip;
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate * Set config(s) and interface(s) to parse based on parse level.
6767c478bd9Sstevel@tonic-gate * Adjust parse_level according to which configs and interfaces are
6777c478bd9Sstevel@tonic-gate * made available by the device.
6787c478bd9Sstevel@tonic-gate */
6797c478bd9Sstevel@tonic-gate state.st_dev_parse_level = usb_reg->dev_parse_level;
6807c478bd9Sstevel@tonic-gate if (usba_set_parse_values(dip, usba_device, &state) != USB_SUCCESS) {
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate usb_reg->dev_parse_level = state.st_dev_parse_level;
6857c478bd9Sstevel@tonic-gate
6867c478bd9Sstevel@tonic-gate /* Preallocate configurations based on parse level. */
6877c478bd9Sstevel@tonic-gate if (usb_reg->dev_parse_level == USB_PARSE_LVL_ALL) {
6887c478bd9Sstevel@tonic-gate usb_reg->dev_n_cfg = usba_device->usb_n_cfgs;
6897c478bd9Sstevel@tonic-gate low_cfg_bound = 0;
6907c478bd9Sstevel@tonic-gate high_cfg_bound = usba_device->usb_n_cfgs;
6917c478bd9Sstevel@tonic-gate } else {
6927c478bd9Sstevel@tonic-gate usb_reg->dev_n_cfg = 1;
6937c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
6947c478bd9Sstevel@tonic-gate low_cfg_bound = usba_device->usb_active_cfg_ndx;
6957c478bd9Sstevel@tonic-gate high_cfg_bound = usba_device->usb_active_cfg_ndx + 1;
6967c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate usb_reg->dev_cfg = state.st_dev_cfg = kmem_zalloc(
699112116d8Sfb (usb_reg->dev_n_cfg * sizeof (usb_cfg_data_t)),
700112116d8Sfb KM_SLEEP);
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate * this_cfg_ndx loops through all configurations presented;
7037c478bd9Sstevel@tonic-gate * state.st_dev_n_cfg limits the cfgs checked to the number desired.
7047c478bd9Sstevel@tonic-gate */
7057c478bd9Sstevel@tonic-gate state.st_dev_n_cfg = 0;
7067c478bd9Sstevel@tonic-gate for (this_cfg_ndx = low_cfg_bound; this_cfg_ndx < high_cfg_bound;
7077c478bd9Sstevel@tonic-gate this_cfg_ndx++) {
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate state.st_curr_raw_descr =
710112116d8Sfb usba_device->usb_cfg_array[this_cfg_ndx];
7117c478bd9Sstevel@tonic-gate ASSERT(state.st_curr_raw_descr != NULL);
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate /* Clear the following for config cloud sanity checking. */
7147c478bd9Sstevel@tonic-gate last_byte = NULL;
7157c478bd9Sstevel@tonic-gate state.st_curr_cfg = NULL;
7167c478bd9Sstevel@tonic-gate state.st_curr_if = NULL;
7177c478bd9Sstevel@tonic-gate state.st_curr_alt = NULL;
7187c478bd9Sstevel@tonic-gate state.st_curr_ep = NULL;
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate do {
7217c478bd9Sstevel@tonic-gate /* All descr have length and type at offset 0 and 1 */
7227c478bd9Sstevel@tonic-gate state.st_curr_raw_descr_len =
7237c478bd9Sstevel@tonic-gate state.st_curr_raw_descr[0];
7247c478bd9Sstevel@tonic-gate state.st_curr_raw_descr_type =
7257c478bd9Sstevel@tonic-gate state.st_curr_raw_descr[1];
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /* First descr in cloud must be a config descr. */
7287c478bd9Sstevel@tonic-gate if ((last_byte == NULL) &&
7297c478bd9Sstevel@tonic-gate (state.st_curr_raw_descr_type !=
7307c478bd9Sstevel@tonic-gate USB_DESCR_TYPE_CFG)) {
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate return (USB_FAILURE);
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate * Bomb if we don't find a new cfg descr when expected.
7377c478bd9Sstevel@tonic-gate * cfg_len_so_far = total_cfg_length = 0 1st time thru.
7387c478bd9Sstevel@tonic-gate */
7397c478bd9Sstevel@tonic-gate if (cfg_len_so_far > state.st_total_cfg_length) {
7407c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL,
7417c478bd9Sstevel@tonic-gate usbai_reg_log_handle,
7427c478bd9Sstevel@tonic-gate "usba_build_descr_tree: Configuration (%d) "
7437c478bd9Sstevel@tonic-gate "larger than wTotalLength (%d).",
7447c478bd9Sstevel@tonic-gate cfg_len_so_far, state.st_total_cfg_length);
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate return (USB_FAILURE);
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_REGISTER,
7507c478bd9Sstevel@tonic-gate usbai_reg_log_handle,
7517c478bd9Sstevel@tonic-gate "usba_build_descr_tree: Process type %d descr "
7527c478bd9Sstevel@tonic-gate "(addr=0x%p)", state.st_curr_raw_descr_type,
753112116d8Sfb (void *)state.st_curr_raw_descr);
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate switch (state.st_curr_raw_descr_type) {
7567c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_CFG:
7577c478bd9Sstevel@tonic-gate cfg_len_so_far = 0;
7587c478bd9Sstevel@tonic-gate process_this_if_tree = B_FALSE;
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate state.st_curr_cfg_str = usba_device->
761112116d8Sfb usb_cfg_str_descr[this_cfg_ndx];
7627c478bd9Sstevel@tonic-gate usba_process_cfg_descr(&state);
7637c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type =
764112116d8Sfb USB_DESCR_TYPE_CFG;
7657c478bd9Sstevel@tonic-gate last_byte = state.st_curr_raw_descr +
7667c478bd9Sstevel@tonic-gate (state.st_total_cfg_length *
7677c478bd9Sstevel@tonic-gate sizeof (uchar_t));
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate break;
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_IF:
7727c478bd9Sstevel@tonic-gate /*
7737c478bd9Sstevel@tonic-gate * process_this_if_tree == TRUE means this
7747c478bd9Sstevel@tonic-gate * interface, plus all eps and c/vs in it are
7757c478bd9Sstevel@tonic-gate * to be processed.
7767c478bd9Sstevel@tonic-gate */
7777c478bd9Sstevel@tonic-gate if (usba_process_if_descr(&state,
778112116d8Sfb &process_this_if_tree) != USB_SUCCESS) {
7797c478bd9Sstevel@tonic-gate
780112116d8Sfb return (USB_FAILURE);
7817c478bd9Sstevel@tonic-gate }
7827c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type =
783112116d8Sfb USB_DESCR_TYPE_IF;
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate break;
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_EP:
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate * Skip if endpoints of a specific interface are
7907c478bd9Sstevel@tonic-gate * desired and this endpoint is associated with
7917c478bd9Sstevel@tonic-gate * a different interface.
7927c478bd9Sstevel@tonic-gate */
7937c478bd9Sstevel@tonic-gate if (process_this_if_tree) {
7947c478bd9Sstevel@tonic-gate if (usba_process_ep_descr(&state) !=
7957c478bd9Sstevel@tonic-gate USB_SUCCESS) {
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate return (USB_FAILURE);
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate state.st_last_processed_descr_type =
800112116d8Sfb USB_DESCR_TYPE_EP;
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate
803ff0e937bSRaymond Chen break;
804993e3fafSRobert Mustacchi
805993e3fafSRobert Mustacchi case USB_DESCR_TYPE_SS_EP_COMP:
806993e3fafSRobert Mustacchi
807993e3fafSRobert Mustacchi /*
808993e3fafSRobert Mustacchi * These entries should always follow an
809993e3fafSRobert Mustacchi * endpoint description. If an endpoint
810993e3fafSRobert Mustacchi * description wasn't the last
811993e3fafSRobert Mustacchi * thing that we found, then we shouldn't
812993e3fafSRobert Mustacchi * process this descriptor.
813993e3fafSRobert Mustacchi */
814993e3fafSRobert Mustacchi if (state.st_last_processed_descr_type ==
815993e3fafSRobert Mustacchi USB_DESCR_TYPE_EP) {
816993e3fafSRobert Mustacchi if (usba_process_ss_ep_comp_descr(
817993e3fafSRobert Mustacchi &state) != USB_SUCCESS) {
818993e3fafSRobert Mustacchi
819993e3fafSRobert Mustacchi return (USB_FAILURE);
820993e3fafSRobert Mustacchi }
821993e3fafSRobert Mustacchi
822993e3fafSRobert Mustacchi state.st_last_processed_descr_type =
823993e3fafSRobert Mustacchi USB_DESCR_TYPE_SS_EP_COMP;
824993e3fafSRobert Mustacchi
825993e3fafSRobert Mustacchi break;
826993e3fafSRobert Mustacchi }
827993e3fafSRobert Mustacchi break;
828993e3fafSRobert Mustacchi
8297c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_STRING:
8307c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL,
8317c478bd9Sstevel@tonic-gate usbai_reg_log_handle,
8327c478bd9Sstevel@tonic-gate "usb_get_dev_data: "
8337c478bd9Sstevel@tonic-gate "Found unexpected str descr at addr 0x%p",
834112116d8Sfb (void *)state.st_curr_raw_descr);
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate break; /* Shouldn't be any here. Skip. */
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate default:
8397c478bd9Sstevel@tonic-gate /*
8407c478bd9Sstevel@tonic-gate * Treat all other descr as class/vendor
8417c478bd9Sstevel@tonic-gate * specific. Skip if c/vs of a specific
8427c478bd9Sstevel@tonic-gate * interface are desired and this c/v is
8437c478bd9Sstevel@tonic-gate * associated with a different one.
844ff0e937bSRaymond Chen * Device level c/vs should always be
845ff0e937bSRaymond Chen * processed, e.g., the security descrs
846ff0e937bSRaymond Chen * for the Host Wire Adapter.
8477c478bd9Sstevel@tonic-gate */
848ff0e937bSRaymond Chen if ((state.st_last_processed_descr_type ==
849ff0e937bSRaymond Chen USB_DESCR_TYPE_CFG) ||
850ff0e937bSRaymond Chen (process_this_if_tree == B_TRUE)) {
8517c478bd9Sstevel@tonic-gate if (usba_process_cv_descr(&state) !=
8527c478bd9Sstevel@tonic-gate USB_SUCCESS) {
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate return (USB_FAILURE);
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate state.st_curr_raw_descr += state.st_curr_raw_descr_len;
8607c478bd9Sstevel@tonic-gate cfg_len_so_far += state.st_curr_raw_descr_len;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate } while (state.st_curr_raw_descr < last_byte);
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate /* Make tree sparse, and put elements in order. */
8667c478bd9Sstevel@tonic-gate usba_order_tree(&state);
8677c478bd9Sstevel@tonic-gate
8687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
8697c478bd9Sstevel@tonic-gate "usba_build_descr_tree done");
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate /*
8767c478bd9Sstevel@tonic-gate * usba_process_cfg_descr:
8777c478bd9Sstevel@tonic-gate * Set up a configuration tree node based on a raw config descriptor.
8787c478bd9Sstevel@tonic-gate *
8797c478bd9Sstevel@tonic-gate * Arguments:
8807c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure.
8817c478bd9Sstevel@tonic-gate *
8827c478bd9Sstevel@tonic-gate * Returns:
8837c478bd9Sstevel@tonic-gate * B_TRUE: the descr processed corresponds to a requested configuration.
8847c478bd9Sstevel@tonic-gate * B_FALSE: the descr processed does not correspond to a requested config.
8857c478bd9Sstevel@tonic-gate */
8867c478bd9Sstevel@tonic-gate static void
usba_process_cfg_descr(usba_reg_state_t * state)8877c478bd9Sstevel@tonic-gate usba_process_cfg_descr(usba_reg_state_t *state)
8887c478bd9Sstevel@tonic-gate {
8897c478bd9Sstevel@tonic-gate usb_cfg_data_t *curr_cfg;
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
8927c478bd9Sstevel@tonic-gate "usba_process_cfg_descr starting");
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate curr_cfg = state->st_curr_cfg =
8957c478bd9Sstevel@tonic-gate &state->st_dev_cfg[state->st_dev_n_cfg++];
8967c478bd9Sstevel@tonic-gate
8977c478bd9Sstevel@tonic-gate /* Parse and store config descriptor proper in the tree. */
8987c478bd9Sstevel@tonic-gate (void) usb_parse_data("2cs5c",
8997c478bd9Sstevel@tonic-gate state->st_curr_raw_descr, state->st_curr_raw_descr_len,
9007c478bd9Sstevel@tonic-gate &curr_cfg->cfg_descr,
9017c478bd9Sstevel@tonic-gate sizeof (usb_cfg_descr_t));
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate state->st_total_cfg_length = curr_cfg->cfg_descr.wTotalLength;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate if (state->st_curr_cfg_str != NULL) {
9067c478bd9Sstevel@tonic-gate curr_cfg->cfg_strsize = strlen(state->st_curr_cfg_str) + 1;
9077c478bd9Sstevel@tonic-gate curr_cfg->cfg_str = kmem_zalloc(curr_cfg->cfg_strsize,
908112116d8Sfb KM_SLEEP);
9097c478bd9Sstevel@tonic-gate (void) strcpy(curr_cfg->cfg_str, state->st_curr_cfg_str);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate curr_cfg->cfg_n_if = curr_cfg->cfg_descr.bNumInterfaces;
9137c478bd9Sstevel@tonic-gate curr_cfg->cfg_if = kmem_zalloc((curr_cfg->cfg_n_if *
914112116d8Sfb sizeof (usb_if_data_t)), KM_SLEEP);
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9177c478bd9Sstevel@tonic-gate "usba_process_cfg_descr done");
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate /*
9227c478bd9Sstevel@tonic-gate * usba_process_if_descr:
9237c478bd9Sstevel@tonic-gate * This processes a raw interface descriptor, and sets up an analogous
9247c478bd9Sstevel@tonic-gate * interface node and child "alternate" nodes (each containing an
9257c478bd9Sstevel@tonic-gate * interface descriptor) in the descriptor tree.
9267c478bd9Sstevel@tonic-gate *
9277c478bd9Sstevel@tonic-gate * It groups all descriptors with the same bInterfaceNumber (alternates)
9287c478bd9Sstevel@tonic-gate * into an array. It makes entries in an interface array, each of which
9297c478bd9Sstevel@tonic-gate * points to an array of alternates.
9307c478bd9Sstevel@tonic-gate *
9317c478bd9Sstevel@tonic-gate * Arguments:
9327c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure.
9337c478bd9Sstevel@tonic-gate * requested_if - Address into which the following is returned:
9347c478bd9Sstevel@tonic-gate * B_TRUE - the processed descr is of a requested interface.
9357c478bd9Sstevel@tonic-gate * B_FALSE - the processed descr if of a non-requested interface.
9367c478bd9Sstevel@tonic-gate *
9377c478bd9Sstevel@tonic-gate * Returns:
9387c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed.
9397c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud.
9407c478bd9Sstevel@tonic-gate */
9417c478bd9Sstevel@tonic-gate static int
usba_process_if_descr(usba_reg_state_t * state,boolean_t * requested_if)9427c478bd9Sstevel@tonic-gate usba_process_if_descr(usba_reg_state_t *state, boolean_t *requested_if)
9437c478bd9Sstevel@tonic-gate {
9447c478bd9Sstevel@tonic-gate char *string;
9457c478bd9Sstevel@tonic-gate usb_if_descr_t *new_if_descr;
9467c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(state->dip);
9477c478bd9Sstevel@tonic-gate int is_root_hub = (usba_device->usb_addr == ROOT_HUB_ADDR);
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9507c478bd9Sstevel@tonic-gate "usba_process_if_descr starting");
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate /* No config preceeds this interface. */
9537c478bd9Sstevel@tonic-gate if (state->st_curr_cfg == NULL) {
9547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
9557c478bd9Sstevel@tonic-gate "usba_process_if_descr found interface after no config.");
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate return (USB_FAILURE);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate new_if_descr = kmem_zalloc(sizeof (usb_if_descr_t), KM_SLEEP);
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate /* Strictly speaking, unpacking is not necessary. Could use bcopy. */
9637c478bd9Sstevel@tonic-gate (void) usb_parse_data("9c", state->st_curr_raw_descr,
964112116d8Sfb state->st_curr_raw_descr_len,
965112116d8Sfb new_if_descr, sizeof (usb_if_descr_t));
9667c478bd9Sstevel@tonic-gate
967cbab2b26Slg /* Check the interface number in case of a malfunction device */
968cbab2b26Slg if (new_if_descr->bInterfaceNumber >= state->st_curr_cfg->cfg_n_if) {
969cbab2b26Slg USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
970cbab2b26Slg "usba_process_if_descr: bInterfaceNumber=%d is not "
971cbab2b26Slg "a valid one", new_if_descr->bInterfaceNumber);
972cbab2b26Slg kmem_free(new_if_descr, sizeof (usb_if_descr_t));
973cbab2b26Slg
974de577e60Svn *requested_if = B_FALSE;
975de577e60Svn
976de577e60Svn return (USB_SUCCESS);
977cbab2b26Slg }
978cbab2b26Slg *requested_if = B_TRUE;
979cbab2b26Slg
9807c478bd9Sstevel@tonic-gate /* Not a requested interface. */
9817c478bd9Sstevel@tonic-gate if ((state->st_if_to_build != new_if_descr->bInterfaceNumber) &&
9827c478bd9Sstevel@tonic-gate (state->st_if_to_build != USBA_ALL)) {
9837c478bd9Sstevel@tonic-gate *requested_if = B_FALSE;
9847c478bd9Sstevel@tonic-gate
9857c478bd9Sstevel@tonic-gate } else {
9867c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt_array;
9877c478bd9Sstevel@tonic-gate uint_t alt_index;
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate /* Point to proper interface node, based on num in descr. */
9907c478bd9Sstevel@tonic-gate state->st_curr_if =
9917c478bd9Sstevel@tonic-gate &state->st_curr_cfg->cfg_if[new_if_descr->bInterfaceNumber];
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate /* Make room for new alternate. */
9947c478bd9Sstevel@tonic-gate alt_index = state->st_curr_if->if_n_alt;
9957c478bd9Sstevel@tonic-gate alt_array = state->st_curr_if->if_alt;
9967c478bd9Sstevel@tonic-gate usba_augment_array((void **)(&alt_array), alt_index,
997112116d8Sfb sizeof (usb_alt_if_data_t));
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gate /* Ptr to the current alt, may be used to attach a c/v to it. */
10007c478bd9Sstevel@tonic-gate state->st_curr_alt = &alt_array[alt_index];
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate bcopy(new_if_descr, &(alt_array[alt_index++].altif_descr),
10037c478bd9Sstevel@tonic-gate sizeof (usb_if_descr_t));
10047c478bd9Sstevel@tonic-gate state->st_curr_if->if_alt = alt_array;
10057c478bd9Sstevel@tonic-gate state->st_curr_if->if_n_alt = alt_index;
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
10087c478bd9Sstevel@tonic-gate if (!is_root_hub) {
10097c478bd9Sstevel@tonic-gate (void) usb_get_string_descr(state->dip, USB_LANG_ID,
10107c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_descr.iInterface,
10117c478bd9Sstevel@tonic-gate string, USB_MAXSTRINGLEN);
10127c478bd9Sstevel@tonic-gate }
10137c478bd9Sstevel@tonic-gate if (string[0] == '\0') {
10147c478bd9Sstevel@tonic-gate (void) strcpy(string, "<none>");
10157c478bd9Sstevel@tonic-gate }
10167c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_strsize = strlen(string) + 1;
10177c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_str = kmem_zalloc(
10187c478bd9Sstevel@tonic-gate state->st_curr_alt->altif_strsize, KM_SLEEP);
10197c478bd9Sstevel@tonic-gate (void) strcpy(state->st_curr_alt->altif_str, string);
10207c478bd9Sstevel@tonic-gate kmem_free(string, USB_MAXSTRINGLEN);
10217c478bd9Sstevel@tonic-gate }
10227c478bd9Sstevel@tonic-gate
10237c478bd9Sstevel@tonic-gate kmem_free(new_if_descr, sizeof (usb_if_descr_t));
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10267c478bd9Sstevel@tonic-gate "usba_process_if_descr done");
10277c478bd9Sstevel@tonic-gate
10287c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate /*
10337c478bd9Sstevel@tonic-gate * usba_process_ep_descr:
10347c478bd9Sstevel@tonic-gate * This processes a raw endpoint descriptor, and sets up an analogous
10357c478bd9Sstevel@tonic-gate * endpoint descriptor node in the descriptor tree.
10367c478bd9Sstevel@tonic-gate *
10377c478bd9Sstevel@tonic-gate * Arguments:
10387c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure.
10397c478bd9Sstevel@tonic-gate *
10407c478bd9Sstevel@tonic-gate * Returns:
10417c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed.
10427c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud.
10437c478bd9Sstevel@tonic-gate */
10447c478bd9Sstevel@tonic-gate static int
usba_process_ep_descr(usba_reg_state_t * state)10457c478bd9Sstevel@tonic-gate usba_process_ep_descr(usba_reg_state_t *state)
10467c478bd9Sstevel@tonic-gate {
10477c478bd9Sstevel@tonic-gate usb_alt_if_data_t *curr_alt = state->st_curr_alt;
10487c478bd9Sstevel@tonic-gate
10497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10507c478bd9Sstevel@tonic-gate "usba_process_ep_descr starting");
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate /* No interface preceeds this endpoint. */
10537c478bd9Sstevel@tonic-gate if (state->st_curr_alt == NULL) {
10547c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10557c478bd9Sstevel@tonic-gate "usba_process_ep_descr: no requested alt before endpt.");
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate return (USB_FAILURE);
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate usba_augment_array((void **)(&curr_alt->altif_ep),
1061112116d8Sfb curr_alt->altif_n_ep, sizeof (usb_ep_data_t));
10627c478bd9Sstevel@tonic-gate
10637c478bd9Sstevel@tonic-gate /* Ptr to the current endpt, may be used to attach a c/v to it. */
10647c478bd9Sstevel@tonic-gate state->st_curr_ep = &curr_alt->altif_ep[curr_alt->altif_n_ep++];
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate (void) usb_parse_data("4csc", state->st_curr_raw_descr,
1067112116d8Sfb state->st_curr_raw_descr_len,
1068112116d8Sfb &state->st_curr_ep->ep_descr, sizeof (usb_ep_descr_t));
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
10717c478bd9Sstevel@tonic-gate "usba_process_ep_descr done");
10727c478bd9Sstevel@tonic-gate
10737c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate
1076993e3fafSRobert Mustacchi /*
1077993e3fafSRobert Mustacchi * usba_process_ss_ep_comp_descr:
1078993e3fafSRobert Mustacchi * This processes a raw endpoint companion descriptor and associates it
1079993e3fafSRobert Mustacchi * inside of an existing endpoint's entry.
1080993e3fafSRobert Mustacchi *
1081993e3fafSRobert Mustacchi * Arguments:
1082993e3fafSRobert Mustacchi * state - Pointer to this module's state structure.
1083993e3fafSRobert Mustacchi *
1084993e3fafSRobert Mustacchi * Returns:
1085993e3fafSRobert Mustacchi * USB_SUCCESS: Descriptor is successfully parsed.
1086993e3fafSRobert Mustacchi * USB_FAILURE: Descriptor is inappropriately placed in config cloud.
1087993e3fafSRobert Mustacchi */
1088993e3fafSRobert Mustacchi static int
usba_process_ss_ep_comp_descr(usba_reg_state_t * state)1089993e3fafSRobert Mustacchi usba_process_ss_ep_comp_descr(usba_reg_state_t *state)
1090993e3fafSRobert Mustacchi {
1091993e3fafSRobert Mustacchi if (state->st_curr_ep == NULL)
1092993e3fafSRobert Mustacchi return (USB_FAILURE);
1093993e3fafSRobert Mustacchi
1094993e3fafSRobert Mustacchi (void) usb_parse_data("4cs", state->st_curr_raw_descr,
1095993e3fafSRobert Mustacchi state->st_curr_raw_descr_len,
1096993e3fafSRobert Mustacchi &state->st_curr_ep->ep_ss_comp,
1097993e3fafSRobert Mustacchi sizeof (usb_ep_ss_comp_descr_t));
1098993e3fafSRobert Mustacchi state->st_curr_ep->ep_ss_valid = B_TRUE;
1099993e3fafSRobert Mustacchi
1100993e3fafSRobert Mustacchi return (USB_SUCCESS);
1101993e3fafSRobert Mustacchi }
1102993e3fafSRobert Mustacchi
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate /*
11057c478bd9Sstevel@tonic-gate * usba_process_cv_descr:
11067c478bd9Sstevel@tonic-gate * This processes a raw endpoint descriptor, and sets up an analogous
11077c478bd9Sstevel@tonic-gate * endpoint descriptor in the descriptor tree. C/Vs are associated with
11087c478bd9Sstevel@tonic-gate * other descriptors they follow in the raw data.
11097c478bd9Sstevel@tonic-gate * last_processed_descr_type indicates the type of descr this c/v follows.
11107c478bd9Sstevel@tonic-gate *
11117c478bd9Sstevel@tonic-gate * Arguments:
11127c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure.
11137c478bd9Sstevel@tonic-gate *
11147c478bd9Sstevel@tonic-gate * Returns:
11157c478bd9Sstevel@tonic-gate * USB_SUCCESS: Descriptor is successfully parsed.
11167c478bd9Sstevel@tonic-gate * USB_FAILURE: Descriptor is inappropriately placed in config cloud.
11177c478bd9Sstevel@tonic-gate */
11187c478bd9Sstevel@tonic-gate static int
usba_process_cv_descr(usba_reg_state_t * state)11197c478bd9Sstevel@tonic-gate usba_process_cv_descr(usba_reg_state_t *state)
11207c478bd9Sstevel@tonic-gate {
11217c478bd9Sstevel@tonic-gate usb_cvs_data_t *curr_cv_descr;
11227c478bd9Sstevel@tonic-gate usb_cvs_data_t **cvs_ptr = NULL;
11237c478bd9Sstevel@tonic-gate uint_t *n_cvs_ptr;
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
11267c478bd9Sstevel@tonic-gate "usba_process_cv_descr starting. Processing c/v for descr type %d",
11277c478bd9Sstevel@tonic-gate state->st_last_processed_descr_type);
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate /*
11307c478bd9Sstevel@tonic-gate * Attach the c/v to a node based on the last descr type processed.
11317c478bd9Sstevel@tonic-gate * Save handles to appropriate c/v node array and count to update.
11327c478bd9Sstevel@tonic-gate */
11337c478bd9Sstevel@tonic-gate switch (state->st_last_processed_descr_type) {
11347c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_CFG:
11357c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_cfg->cfg_n_cvs;
11367c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_cfg->cfg_cvs;
11377c478bd9Sstevel@tonic-gate break;
11387c478bd9Sstevel@tonic-gate
11397c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_IF:
11407c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_alt->altif_n_cvs;
11417c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_alt->altif_cvs;
11427c478bd9Sstevel@tonic-gate break;
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate case USB_DESCR_TYPE_EP:
1145b1c06e09SRobert Mustacchi case USB_DESCR_TYPE_SS_EP_COMP:
11467c478bd9Sstevel@tonic-gate n_cvs_ptr = &state->st_curr_ep->ep_n_cvs;
11477c478bd9Sstevel@tonic-gate cvs_ptr = &state->st_curr_ep->ep_cvs;
11487c478bd9Sstevel@tonic-gate break;
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate default:
11517c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_ALL, usbai_reg_log_handle,
11527c478bd9Sstevel@tonic-gate "usba_process_cv_descr: Type of last descriptor unknown. ");
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate return (USB_FAILURE);
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate usba_augment_array((void **)cvs_ptr, *n_cvs_ptr,
1158112116d8Sfb sizeof (usb_cvs_data_t));
11597c478bd9Sstevel@tonic-gate curr_cv_descr = &(*cvs_ptr)[(*n_cvs_ptr)++];
11607c478bd9Sstevel@tonic-gate
11617c478bd9Sstevel@tonic-gate curr_cv_descr->cvs_buf =
1162112116d8Sfb kmem_zalloc(state->st_curr_raw_descr_len, KM_SLEEP);
11637c478bd9Sstevel@tonic-gate curr_cv_descr->cvs_buf_len = state->st_curr_raw_descr_len;
11647c478bd9Sstevel@tonic-gate bcopy(state->st_curr_raw_descr, curr_cv_descr->cvs_buf,
11657c478bd9Sstevel@tonic-gate state->st_curr_raw_descr_len);
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
11687c478bd9Sstevel@tonic-gate "usba_process_cv_descr done");
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
11717c478bd9Sstevel@tonic-gate }
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate /*
11757c478bd9Sstevel@tonic-gate * usba_set_parse_values:
11767c478bd9Sstevel@tonic-gate * Based on parse level, set the configuration(s) and interface(s) to build
11777c478bd9Sstevel@tonic-gate *
11787c478bd9Sstevel@tonic-gate * Returned configuration value can be USBA_ALL indicating to build all
11797c478bd9Sstevel@tonic-gate * configurations. Likewise for the returned interface value.
11807c478bd9Sstevel@tonic-gate *
11817c478bd9Sstevel@tonic-gate * Arguments:
11827c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the device
11837c478bd9Sstevel@tonic-gate * usba_device - pointer to usba_device structure of the device
11847c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure.
11857c478bd9Sstevel@tonic-gate * if no specific config specified, default to all config
11867c478bd9Sstevel@tonic-gate * if no specific interface specified, default to all.
11877c478bd9Sstevel@tonic-gate * if_to_build and config_to_build are modified.
11887c478bd9Sstevel@tonic-gate * dev_parse_level may be modified.
11897c478bd9Sstevel@tonic-gate *
11907c478bd9Sstevel@tonic-gate * Returns:
11917c478bd9Sstevel@tonic-gate * USB_SUCCESS - success
11927c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - state->st_dev_parse_level is invalid.
11937c478bd9Sstevel@tonic-gate */
11947c478bd9Sstevel@tonic-gate static int
usba_set_parse_values(dev_info_t * dip,usba_device_t * usba_device,usba_reg_state_t * state)11957c478bd9Sstevel@tonic-gate usba_set_parse_values(dev_info_t *dip, usba_device_t *usba_device,
11967c478bd9Sstevel@tonic-gate usba_reg_state_t *state)
11977c478bd9Sstevel@tonic-gate {
11987c478bd9Sstevel@tonic-gate /* Default to *all* in case configuration# prop not set. */
11997c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
12007c478bd9Sstevel@tonic-gate state->st_cfg_to_build = usba_device->usb_active_cfg_ndx;
12017c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
12027c478bd9Sstevel@tonic-gate if (state->st_cfg_to_build == USBA_DEV_CONFIG_INDEX_UNDEFINED) {
12037c478bd9Sstevel@tonic-gate state->st_cfg_to_build = USBA_ALL;
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate state->st_if_to_build = usb_get_if_number(dip);
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate switch (state->st_dev_parse_level) {
12087c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_ALL: /* Parse all configurations */
12097c478bd9Sstevel@tonic-gate state->st_cfg_to_build = USBA_ALL;
12107c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL;
12117c478bd9Sstevel@tonic-gate break;
12127c478bd9Sstevel@tonic-gate
12137c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_CFG: /* Parse all interfaces of a */
12147c478bd9Sstevel@tonic-gate /* specific configuration. */
12157c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL;
12167c478bd9Sstevel@tonic-gate break;
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate case USB_PARSE_LVL_IF: /* Parse configured interface only */
12197c478bd9Sstevel@tonic-gate if (state->st_if_to_build < 0) {
12207c478bd9Sstevel@tonic-gate state->st_if_to_build = USBA_ALL;
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate break;
12237c478bd9Sstevel@tonic-gate
12247c478bd9Sstevel@tonic-gate default:
12257c478bd9Sstevel@tonic-gate
12267c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate /*
12307c478bd9Sstevel@tonic-gate * Set parse level to identify this tree properly, regardless of what
12317c478bd9Sstevel@tonic-gate * the caller thought the tree would have.
12327c478bd9Sstevel@tonic-gate */
12337c478bd9Sstevel@tonic-gate if ((state->st_if_to_build == USBA_ALL) &&
12347c478bd9Sstevel@tonic-gate (state->st_dev_parse_level == USB_PARSE_LVL_IF)) {
12357c478bd9Sstevel@tonic-gate state->st_dev_parse_level = USB_PARSE_LVL_CFG;
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate if ((state->st_cfg_to_build == USBA_ALL) &&
12387c478bd9Sstevel@tonic-gate (state->st_dev_parse_level == USB_PARSE_LVL_CFG)) {
12397c478bd9Sstevel@tonic-gate state->st_dev_parse_level = USB_PARSE_LVL_ALL;
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate /*
12477c478bd9Sstevel@tonic-gate * usba_kmem_realloc:
12487c478bd9Sstevel@tonic-gate * Resize dynamic memory. Copy contents of old area to
12497c478bd9Sstevel@tonic-gate * beginning of new area.
12507c478bd9Sstevel@tonic-gate *
12517c478bd9Sstevel@tonic-gate * Arguments:
12527c478bd9Sstevel@tonic-gate * old_mem - pointer to old memory area.
12537c478bd9Sstevel@tonic-gate * old_size - size of old memory area. 0 is OK.
12547c478bd9Sstevel@tonic-gate * new_size - size desired.
12557c478bd9Sstevel@tonic-gate *
12567c478bd9Sstevel@tonic-gate * Returns:
12577c478bd9Sstevel@tonic-gate * pointer to new memory area.
12587c478bd9Sstevel@tonic-gate */
12597c478bd9Sstevel@tonic-gate static void*
usba_kmem_realloc(void * old_mem,int old_size,int new_size)12607c478bd9Sstevel@tonic-gate usba_kmem_realloc(void* old_mem, int old_size, int new_size)
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate void *new_mem = NULL;
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate if (new_size > 0) {
12657c478bd9Sstevel@tonic-gate new_mem = kmem_zalloc(new_size, KM_SLEEP);
12667c478bd9Sstevel@tonic-gate if (old_size > 0) {
12677c478bd9Sstevel@tonic-gate bcopy(old_mem, new_mem,
12687c478bd9Sstevel@tonic-gate min(old_size, new_size));
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate
12727c478bd9Sstevel@tonic-gate if (old_size > 0) {
12737c478bd9Sstevel@tonic-gate kmem_free(old_mem, old_size);
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate return (new_mem);
12777c478bd9Sstevel@tonic-gate }
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate /*
12817c478bd9Sstevel@tonic-gate * usba_augment_array:
12827c478bd9Sstevel@tonic-gate * Add a new element on the end of an array.
12837c478bd9Sstevel@tonic-gate *
12847c478bd9Sstevel@tonic-gate * Arguments:
12857c478bd9Sstevel@tonic-gate * addr - ptr to the array address. Array addr will change.
12867c478bd9Sstevel@tonic-gate * n_elements - array element count.
12877c478bd9Sstevel@tonic-gate * element_size - size of an array element
12887c478bd9Sstevel@tonic-gate */
12897c478bd9Sstevel@tonic-gate static void
usba_augment_array(void ** addr,uint_t n_elements,uint_t element_size)12907c478bd9Sstevel@tonic-gate usba_augment_array(void **addr, uint_t n_elements, uint_t element_size)
12917c478bd9Sstevel@tonic-gate {
12927c478bd9Sstevel@tonic-gate *addr = usba_kmem_realloc(*addr, (n_elements * element_size),
1293112116d8Sfb ((n_elements + 1) * element_size));
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate * usba_make_alts_sparse:
12997c478bd9Sstevel@tonic-gate * Disburse alternate array elements such that they are at the proper array
13007c478bd9Sstevel@tonic-gate * indices for which alt they represent. It is assumed that all key values
13017c478bd9Sstevel@tonic-gate * used for ordering the elements are positive. Original array space may
13027c478bd9Sstevel@tonic-gate * be freed and new space allocated.
13037c478bd9Sstevel@tonic-gate *
13047c478bd9Sstevel@tonic-gate * Arguments:
13057c478bd9Sstevel@tonic-gate * array - pointer to alternates array; may be modified
13067c478bd9Sstevel@tonic-gate * n_elements - number of elements in the array; may be modified
13077c478bd9Sstevel@tonic-gate */
13087c478bd9Sstevel@tonic-gate static void
usba_make_alts_sparse(usb_alt_if_data_t ** array,uint_t * n_elements)13097c478bd9Sstevel@tonic-gate usba_make_alts_sparse(usb_alt_if_data_t **array, uint_t *n_elements)
13107c478bd9Sstevel@tonic-gate {
13117c478bd9Sstevel@tonic-gate uint_t n_orig_elements = *n_elements;
13127c478bd9Sstevel@tonic-gate uint8_t smallest_value;
13137c478bd9Sstevel@tonic-gate uint8_t largest_value;
13147c478bd9Sstevel@tonic-gate uint8_t curr_value;
13157c478bd9Sstevel@tonic-gate uint_t in_order = 0;
1316*0d2006e4SRobert Mustacchi usb_alt_if_data_t *orig_addr; /* Non-sparse array base ptr */
13177c478bd9Sstevel@tonic-gate usb_alt_if_data_t *repl_array; /* Base ptr to sparse array */
13187c478bd9Sstevel@tonic-gate uint_t n_repl_elements; /* Number elements in the new array */
13197c478bd9Sstevel@tonic-gate uint_t i;
13207c478bd9Sstevel@tonic-gate
13217c478bd9Sstevel@tonic-gate /* Check for a null array. */
13227c478bd9Sstevel@tonic-gate if ((array == NULL) || (n_orig_elements == 0)) {
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate return;
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate
13277c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
13287c478bd9Sstevel@tonic-gate "make_sparse: array=0x%p, n_orig_elements=%d",
1329112116d8Sfb (void *)array, n_orig_elements);
13307c478bd9Sstevel@tonic-gate
1331*0d2006e4SRobert Mustacchi orig_addr = *array;
13327c478bd9Sstevel@tonic-gate curr_value = orig_addr[0].altif_descr.bAlternateSetting;
13337c478bd9Sstevel@tonic-gate smallest_value = largest_value = curr_value;
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate /* Figure the low-high range of the array. */
13367c478bd9Sstevel@tonic-gate for (i = 1; i < n_orig_elements; i++) {
13377c478bd9Sstevel@tonic-gate curr_value = orig_addr[i].altif_descr.bAlternateSetting;
13387c478bd9Sstevel@tonic-gate if (curr_value < smallest_value) {
13397c478bd9Sstevel@tonic-gate smallest_value = curr_value;
13407c478bd9Sstevel@tonic-gate } else if (curr_value > largest_value) {
13417c478bd9Sstevel@tonic-gate in_order++;
13427c478bd9Sstevel@tonic-gate largest_value = curr_value;
13437c478bd9Sstevel@tonic-gate }
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1346112116d8Sfb "make_sparse: largest=%d, smallest=%d, "
1347112116d8Sfb "order=%d",
1348112116d8Sfb largest_value, smallest_value, in_order);
13497c478bd9Sstevel@tonic-gate
13507c478bd9Sstevel@tonic-gate n_repl_elements = largest_value + 1;
13517c478bd9Sstevel@tonic-gate
13527c478bd9Sstevel@tonic-gate /*
13537c478bd9Sstevel@tonic-gate * No holes to leave, array starts at zero, and everything is already
13547c478bd9Sstevel@tonic-gate * in order. Just return original array.
13557c478bd9Sstevel@tonic-gate */
13567c478bd9Sstevel@tonic-gate if ((n_repl_elements == n_orig_elements) &&
13577c478bd9Sstevel@tonic-gate ((in_order + 1) == n_orig_elements)) {
13587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1359112116d8Sfb "No holes");
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate return;
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate /* Allocate zeroed space for the array. */
13657c478bd9Sstevel@tonic-gate repl_array = kmem_zalloc(
1366112116d8Sfb (n_repl_elements * sizeof (usb_alt_if_data_t)), KM_SLEEP);
13677c478bd9Sstevel@tonic-gate
13687c478bd9Sstevel@tonic-gate /* Now fill in the array. */
13697c478bd9Sstevel@tonic-gate for (i = 0; i < n_orig_elements; i++) {
13707c478bd9Sstevel@tonic-gate curr_value = orig_addr[i].altif_descr.bAlternateSetting;
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate /* Place in sparse array based on key. */
13737c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
1374112116d8Sfb "move %lu bytes (key %d) from 0x%p to 0x%p",
13758793b36bSNick Todd (unsigned long)sizeof (usb_alt_if_data_t), curr_value,
1376112116d8Sfb (void *)&orig_addr[i], (void *)&repl_array[curr_value]);
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate bcopy((char *)&orig_addr[i], (char *)&repl_array[curr_value],
13797c478bd9Sstevel@tonic-gate sizeof (usb_alt_if_data_t));
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate
13827c478bd9Sstevel@tonic-gate kmem_free(*array, sizeof (usb_alt_if_data_t) * n_orig_elements);
13837c478bd9Sstevel@tonic-gate *array = repl_array;
13847c478bd9Sstevel@tonic-gate *n_elements = n_repl_elements;
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate /*
13897c478bd9Sstevel@tonic-gate * usba_order_tree:
13907c478bd9Sstevel@tonic-gate * Take a tree as built by usba_build_descr_tree and make sure the key
13917c478bd9Sstevel@tonic-gate * values of all elements match their indeces. Proper order is implied.
13927c478bd9Sstevel@tonic-gate *
13937c478bd9Sstevel@tonic-gate * Arguments:
13947c478bd9Sstevel@tonic-gate * state - Pointer to this module's state structure.
13957c478bd9Sstevel@tonic-gate */
13967c478bd9Sstevel@tonic-gate static void
usba_order_tree(usba_reg_state_t * state)13977c478bd9Sstevel@tonic-gate usba_order_tree(usba_reg_state_t *state)
13987c478bd9Sstevel@tonic-gate {
13997c478bd9Sstevel@tonic-gate usb_cfg_data_t *this_cfg;
14007c478bd9Sstevel@tonic-gate usb_if_data_t *this_if;
14017c478bd9Sstevel@tonic-gate uint_t n_cfgs = state->st_dev_n_cfg;
14027c478bd9Sstevel@tonic-gate uint_t cfg;
14037c478bd9Sstevel@tonic-gate uint_t which_if;
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
14067c478bd9Sstevel@tonic-gate "usba_order_tree:");
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < n_cfgs; cfg++) {
14097c478bd9Sstevel@tonic-gate this_cfg = &state->st_dev_cfg[cfg];
14107c478bd9Sstevel@tonic-gate
14117c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < this_cfg->cfg_n_if; which_if++) {
14127c478bd9Sstevel@tonic-gate this_if = this_cfg->cfg_if;
14137c478bd9Sstevel@tonic-gate usba_make_alts_sparse(&this_if->if_alt,
1414112116d8Sfb &this_if->if_n_alt);
14157c478bd9Sstevel@tonic-gate }
14167c478bd9Sstevel@tonic-gate }
14177c478bd9Sstevel@tonic-gate }
14187c478bd9Sstevel@tonic-gate
14197c478bd9Sstevel@tonic-gate
14207c478bd9Sstevel@tonic-gate /*
14217c478bd9Sstevel@tonic-gate * usb_free_descr_tree:
14227c478bd9Sstevel@tonic-gate * Take down the configuration tree. Called internally and can be called
14237c478bd9Sstevel@tonic-gate * from a driver standalone to take the tree down while leaving the rest
14247c478bd9Sstevel@tonic-gate * of the registration intact.
14257c478bd9Sstevel@tonic-gate *
14267c478bd9Sstevel@tonic-gate * Arguments:
14277c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the device
14287c478bd9Sstevel@tonic-gate * dev_data - pointer to registration data containing the tree.
14297c478bd9Sstevel@tonic-gate */
14307c478bd9Sstevel@tonic-gate void
usb_free_descr_tree(dev_info_t * dip,usb_client_dev_data_t * dev_data)14317c478bd9Sstevel@tonic-gate usb_free_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data)
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate usb_cfg_data_t *cfg_array;
14347c478bd9Sstevel@tonic-gate int n_cfgs;
14357c478bd9Sstevel@tonic-gate int cfg;
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate if ((dip == NULL) || (dev_data == NULL)) {
14387c478bd9Sstevel@tonic-gate
14397c478bd9Sstevel@tonic-gate return;
14407c478bd9Sstevel@tonic-gate }
14417c478bd9Sstevel@tonic-gate cfg_array = dev_data->dev_cfg;
14427c478bd9Sstevel@tonic-gate n_cfgs = dev_data->dev_n_cfg;
14437c478bd9Sstevel@tonic-gate
14447c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
14457c478bd9Sstevel@tonic-gate "usb_free_descr_tree starting for %s%d",
14467c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip));
14477c478bd9Sstevel@tonic-gate
14487c478bd9Sstevel@tonic-gate for (cfg = 0; cfg < n_cfgs; cfg++) {
14497c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_if) {
14507c478bd9Sstevel@tonic-gate usba_free_if_array(cfg_array[cfg].cfg_if,
1451112116d8Sfb cfg_array[cfg].cfg_n_if);
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_cvs) {
14547c478bd9Sstevel@tonic-gate usba_free_cv_array(cfg_array[cfg].cfg_cvs,
1455112116d8Sfb cfg_array[cfg].cfg_n_cvs);
14567c478bd9Sstevel@tonic-gate }
14577c478bd9Sstevel@tonic-gate if (cfg_array[cfg].cfg_str) {
14587c478bd9Sstevel@tonic-gate kmem_free(cfg_array[cfg].cfg_str,
1459112116d8Sfb cfg_array[cfg].cfg_strsize);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate
14637c478bd9Sstevel@tonic-gate if (cfg_array) {
14647c478bd9Sstevel@tonic-gate kmem_free(cfg_array, (sizeof (usb_cfg_data_t) * n_cfgs));
14657c478bd9Sstevel@tonic-gate }
14667c478bd9Sstevel@tonic-gate
14677c478bd9Sstevel@tonic-gate dev_data->dev_parse_level = USB_PARSE_LVL_NONE;
14687c478bd9Sstevel@tonic-gate dev_data->dev_n_cfg = 0;
14697c478bd9Sstevel@tonic-gate dev_data->dev_cfg = NULL;
14707c478bd9Sstevel@tonic-gate dev_data->dev_curr_cfg = NULL;
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_REGISTER, usbai_reg_log_handle,
14737c478bd9Sstevel@tonic-gate "usb_free_descr_tree done");
14747c478bd9Sstevel@tonic-gate }
14757c478bd9Sstevel@tonic-gate
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate /*
14787c478bd9Sstevel@tonic-gate * usba_free_if_array:
14797c478bd9Sstevel@tonic-gate * Free a configuration's array of interface nodes and their subtrees of
14807c478bd9Sstevel@tonic-gate * interface alternate, endpoint and c/v descriptors.
14817c478bd9Sstevel@tonic-gate *
14827c478bd9Sstevel@tonic-gate * Arguments:
14837c478bd9Sstevel@tonic-gate * if_array - pointer to array of interfaces to remove.
14847c478bd9Sstevel@tonic-gate * n_ifs - number of elements in the array to remove.
14857c478bd9Sstevel@tonic-gate */
14867c478bd9Sstevel@tonic-gate static void
usba_free_if_array(usb_if_data_t * if_array,uint_t n_ifs)14877c478bd9Sstevel@tonic-gate usba_free_if_array(usb_if_data_t *if_array, uint_t n_ifs)
14887c478bd9Sstevel@tonic-gate {
14897c478bd9Sstevel@tonic-gate uint_t which_if;
14907c478bd9Sstevel@tonic-gate uint_t which_alt;
14917c478bd9Sstevel@tonic-gate uint_t n_alts;
14927c478bd9Sstevel@tonic-gate usb_alt_if_data_t *altif;
14937c478bd9Sstevel@tonic-gate
14947c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < n_ifs; which_if++) {
14957c478bd9Sstevel@tonic-gate n_alts = if_array[which_if].if_n_alt;
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate /* Every interface has at least one alternate. */
14987c478bd9Sstevel@tonic-gate for (which_alt = 0; which_alt < n_alts; which_alt++) {
14997c478bd9Sstevel@tonic-gate altif = &if_array[which_if].if_alt[which_alt];
15007c478bd9Sstevel@tonic-gate usba_free_ep_array(altif->altif_ep, altif->altif_n_ep);
15017c478bd9Sstevel@tonic-gate usba_free_cv_array(altif->altif_cvs,
1502112116d8Sfb altif->altif_n_cvs);
15037c478bd9Sstevel@tonic-gate kmem_free(altif->altif_str, altif->altif_strsize);
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate
15067c478bd9Sstevel@tonic-gate kmem_free(if_array[which_if].if_alt,
15077c478bd9Sstevel@tonic-gate (sizeof (usb_alt_if_data_t) * n_alts));
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate
15107c478bd9Sstevel@tonic-gate /* Free the interface array itself. */
15117c478bd9Sstevel@tonic-gate kmem_free(if_array, (sizeof (usb_if_data_t) * n_ifs));
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate /*
15167c478bd9Sstevel@tonic-gate * usba_free_ep_array:
15177c478bd9Sstevel@tonic-gate * Free an array of endpoint nodes and their subtrees of c/v descriptors.
15187c478bd9Sstevel@tonic-gate *
15197c478bd9Sstevel@tonic-gate * Arguments:
15207c478bd9Sstevel@tonic-gate * ep_array - pointer to array of endpoints to remove.
15217c478bd9Sstevel@tonic-gate * n_eps - number of elements in the array to remove.
15227c478bd9Sstevel@tonic-gate */
15237c478bd9Sstevel@tonic-gate static void
usba_free_ep_array(usb_ep_data_t * ep_array,uint_t n_eps)15247c478bd9Sstevel@tonic-gate usba_free_ep_array(usb_ep_data_t *ep_array, uint_t n_eps)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate uint_t ep;
15277c478bd9Sstevel@tonic-gate
15287c478bd9Sstevel@tonic-gate for (ep = 0; ep < n_eps; ep++) {
15297c478bd9Sstevel@tonic-gate usba_free_cv_array(ep_array[ep].ep_cvs, ep_array[ep].ep_n_cvs);
15307c478bd9Sstevel@tonic-gate }
15317c478bd9Sstevel@tonic-gate
15327c478bd9Sstevel@tonic-gate kmem_free(ep_array, (sizeof (usb_ep_data_t) * n_eps));
15337c478bd9Sstevel@tonic-gate }
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate
15367c478bd9Sstevel@tonic-gate /*
15377c478bd9Sstevel@tonic-gate * usba_free_cv_array:
15387c478bd9Sstevel@tonic-gate * Free an array of class/vendor (c/v) descriptor nodes.
15397c478bd9Sstevel@tonic-gate *
15407c478bd9Sstevel@tonic-gate * Arguments:
15417c478bd9Sstevel@tonic-gate * cv_array - pointer to array of c/v nodes to remove.
15427c478bd9Sstevel@tonic-gate * n_cvs - number of elements in the array to remove.
15437c478bd9Sstevel@tonic-gate */
15447c478bd9Sstevel@tonic-gate static void
usba_free_cv_array(usb_cvs_data_t * cv_array,uint_t n_cvs)15457c478bd9Sstevel@tonic-gate usba_free_cv_array(usb_cvs_data_t *cv_array, uint_t n_cvs)
15467c478bd9Sstevel@tonic-gate {
15477c478bd9Sstevel@tonic-gate uint_t cv_node;
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate /* Free data areas hanging off of each c/v descriptor. */
15507c478bd9Sstevel@tonic-gate for (cv_node = 0; cv_node < n_cvs; cv_node++) {
15517c478bd9Sstevel@tonic-gate kmem_free(cv_array[cv_node].cvs_buf,
1552112116d8Sfb cv_array[cv_node].cvs_buf_len);
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate /* Free the array of cv descriptors. */
15567c478bd9Sstevel@tonic-gate kmem_free(cv_array, (sizeof (usb_cvs_data_t) * n_cvs));
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate
15597c478bd9Sstevel@tonic-gate
15607c478bd9Sstevel@tonic-gate /*
15617c478bd9Sstevel@tonic-gate * usb_log_descr_tree:
15627c478bd9Sstevel@tonic-gate * Log to the usba_debug_buf a descriptor tree as returned by
15637c478bd9Sstevel@tonic-gate * usbai_register_client.
15647c478bd9Sstevel@tonic-gate *
15657c478bd9Sstevel@tonic-gate * Arguments:
15667c478bd9Sstevel@tonic-gate * dev_data - pointer to registration area containing the tree
15677c478bd9Sstevel@tonic-gate * log_handle - pointer to log handle to use for dumping.
15687c478bd9Sstevel@tonic-gate * level - print level, one of USB_LOG_L0 ... USB_LOG_L4
15697c478bd9Sstevel@tonic-gate * Please see usb_log(9F) for details.
15707c478bd9Sstevel@tonic-gate * mask - print mask. Please see usb_log(9F) for details.
15717c478bd9Sstevel@tonic-gate *
15727c478bd9Sstevel@tonic-gate * Returns:
15737c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped
15747c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context
15757c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given
15767c478bd9Sstevel@tonic-gate */
15777c478bd9Sstevel@tonic-gate int
usb_log_descr_tree(usb_client_dev_data_t * dev_data,usb_log_handle_t log_handle,uint_t level,uint_t mask)15787c478bd9Sstevel@tonic-gate usb_log_descr_tree(usb_client_dev_data_t *dev_data,
15797c478bd9Sstevel@tonic-gate usb_log_handle_t log_handle, uint_t level, uint_t mask)
15807c478bd9Sstevel@tonic-gate {
15817c478bd9Sstevel@tonic-gate return (usba_dump_descr_tree(NULL, dev_data, log_handle, level, mask));
15827c478bd9Sstevel@tonic-gate }
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate
15857c478bd9Sstevel@tonic-gate /*
15867c478bd9Sstevel@tonic-gate * usb_print_descr_tree:
15877c478bd9Sstevel@tonic-gate * Print to the screen a descriptor tree as returned by
15887c478bd9Sstevel@tonic-gate * usbai_register_client.
15897c478bd9Sstevel@tonic-gate *
15907c478bd9Sstevel@tonic-gate * Arguments:
15917c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client
15927c478bd9Sstevel@tonic-gate * dev_data - pointer to registration area containing the tree
15937c478bd9Sstevel@tonic-gate *
15947c478bd9Sstevel@tonic-gate * Returns:
15957c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped
15967c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context
15977c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given
15987c478bd9Sstevel@tonic-gate */
15997c478bd9Sstevel@tonic-gate int
usb_print_descr_tree(dev_info_t * dip,usb_client_dev_data_t * dev_data)16007c478bd9Sstevel@tonic-gate usb_print_descr_tree(dev_info_t *dip, usb_client_dev_data_t *dev_data)
16017c478bd9Sstevel@tonic-gate {
16027c478bd9Sstevel@tonic-gate return (usba_dump_descr_tree(dip, dev_data, NULL, 0, 0));
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate
16057c478bd9Sstevel@tonic-gate
16067c478bd9Sstevel@tonic-gate /*
16077c478bd9Sstevel@tonic-gate * usba_dump_descr_tree:
16087c478bd9Sstevel@tonic-gate * Dump a descriptor tree.
16097c478bd9Sstevel@tonic-gate *
16107c478bd9Sstevel@tonic-gate * Arguments:
16117c478bd9Sstevel@tonic-gate * dip - pointer to devinfo of the client. Used when no
16127c478bd9Sstevel@tonic-gate * log_handle argument given.
16137c478bd9Sstevel@tonic-gate * usb_reg - pointer to registration area containing the tree
16147c478bd9Sstevel@tonic-gate * log_handle - pointer to log handle to use for dumping. If NULL,
16157c478bd9Sstevel@tonic-gate * use internal log handle, which dumps to screen.
16167c478bd9Sstevel@tonic-gate * level - print level, one of USB_LOG_L0 ... USB_LOG_L4
16177c478bd9Sstevel@tonic-gate * Used only when log_handle provided.
16187c478bd9Sstevel@tonic-gate * mask - print mask, used when log_handle argument provided.
16197c478bd9Sstevel@tonic-gate *
16207c478bd9Sstevel@tonic-gate * Returns:
16217c478bd9Sstevel@tonic-gate * USB_SUCCESS - tree successfully dumped
16227c478bd9Sstevel@tonic-gate * USB_INVALID_CONTEXT - called from callback context
16237c478bd9Sstevel@tonic-gate * USB_INVALID_ARGS - bad arguments given
16247c478bd9Sstevel@tonic-gate */
16257c478bd9Sstevel@tonic-gate static int
usba_dump_descr_tree(dev_info_t * dip,usb_client_dev_data_t * usb_reg,usb_log_handle_t log_handle,uint_t level,uint_t mask)16267c478bd9Sstevel@tonic-gate usba_dump_descr_tree(dev_info_t *dip, usb_client_dev_data_t *usb_reg,
16277c478bd9Sstevel@tonic-gate usb_log_handle_t log_handle, uint_t level, uint_t mask)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate usb_log_handle_t dump_handle;
16307c478bd9Sstevel@tonic-gate uint_t dump_level;
16317c478bd9Sstevel@tonic-gate uint_t dump_mask;
16327c478bd9Sstevel@tonic-gate int which_config; /* Counters. */
16337c478bd9Sstevel@tonic-gate int which_if;
16347c478bd9Sstevel@tonic-gate int which_cv;
16357c478bd9Sstevel@tonic-gate usb_cfg_data_t *config; /* ptr to current configuration tree node */
16367c478bd9Sstevel@tonic-gate usb_cfg_descr_t *config_descr; /* and its USB descriptor. */
16377c478bd9Sstevel@tonic-gate char *string;
16387c478bd9Sstevel@tonic-gate char *name_string = NULL;
1639*0d2006e4SRobert Mustacchi int name_string_size = 0;
16407c478bd9Sstevel@tonic-gate
16417c478bd9Sstevel@tonic-gate if ((usb_reg == NULL) || ((log_handle == NULL) && (dip == NULL))) {
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate
16467c478bd9Sstevel@tonic-gate /*
16477c478bd9Sstevel@tonic-gate * To keep calling this simple, kmem_zalloc with the sleep flag always.
16487c478bd9Sstevel@tonic-gate * This means no interrupt context is allowed.
16497c478bd9Sstevel@tonic-gate */
16507c478bd9Sstevel@tonic-gate if (servicing_interrupt()) {
16517c478bd9Sstevel@tonic-gate
16527c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT);
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate
16557c478bd9Sstevel@tonic-gate string = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
16567c478bd9Sstevel@tonic-gate
16577c478bd9Sstevel@tonic-gate if (log_handle != NULL) {
16587c478bd9Sstevel@tonic-gate dump_level = level;
16597c478bd9Sstevel@tonic-gate dump_mask = mask;
16607c478bd9Sstevel@tonic-gate dump_handle = log_handle;
16617c478bd9Sstevel@tonic-gate } else {
16627c478bd9Sstevel@tonic-gate dump_level = USB_LOG_L1;
16637c478bd9Sstevel@tonic-gate dump_mask = DPRINT_MASK_ALL;
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate /* Build device name string. */
16667c478bd9Sstevel@tonic-gate (void) snprintf(string, USB_MAXSTRINGLEN,
1667112116d8Sfb "Port%d", usb_get_addr(dip));
16687c478bd9Sstevel@tonic-gate name_string_size = strlen(string) + 1;
16697c478bd9Sstevel@tonic-gate name_string = kmem_zalloc(name_string_size, KM_SLEEP);
16707c478bd9Sstevel@tonic-gate (void) strcpy(name_string, string);
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate /* Allocate a log handle specifying the name string. */
16737c478bd9Sstevel@tonic-gate dump_handle = usb_alloc_log_hdl(NULL, name_string,
1674112116d8Sfb &dump_level, &dump_mask, NULL,
1675112116d8Sfb USB_FLAGS_SLEEP);
16767c478bd9Sstevel@tonic-gate }
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
16797c478bd9Sstevel@tonic-gate "USB descriptor tree for %s %s",
16807c478bd9Sstevel@tonic-gate (usb_reg->dev_mfg != NULL ? usb_reg->dev_mfg : ""),
16817c478bd9Sstevel@tonic-gate (usb_reg->dev_product != NULL ? usb_reg->dev_product : ""));
16827c478bd9Sstevel@tonic-gate if (usb_reg->dev_n_cfg == 0) {
16837c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
16847c478bd9Sstevel@tonic-gate "No descriptor tree present");
16857c478bd9Sstevel@tonic-gate } else {
16867c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
16877c478bd9Sstevel@tonic-gate "highest configuration found=%d", usb_reg->dev_n_cfg - 1);
16887c478bd9Sstevel@tonic-gate }
16897c478bd9Sstevel@tonic-gate
16907c478bd9Sstevel@tonic-gate for (which_config = 0; which_config < usb_reg->dev_n_cfg;
16917c478bd9Sstevel@tonic-gate which_config++) {
16927c478bd9Sstevel@tonic-gate config = &usb_reg->dev_cfg[which_config];
16937c478bd9Sstevel@tonic-gate config_descr = &config->cfg_descr;
16947c478bd9Sstevel@tonic-gate if (config_descr->bLength == 0) {
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate continue;
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) {
16997c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, " ");
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
1702112116d8Sfb "Configuration #%d (Addr= 0x%p)", which_config,
1703112116d8Sfb (void *)config);
17047c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17057c478bd9Sstevel@tonic-gate "String descr=%s", config->cfg_str);
17067c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17077c478bd9Sstevel@tonic-gate "config descr: len=%d tp=%d totLen=%d numIf=%d "
17087c478bd9Sstevel@tonic-gate "cfgVal=%d att=0x%x pwr=%d",
17097c478bd9Sstevel@tonic-gate config_descr->bLength, config_descr->bDescriptorType,
17107c478bd9Sstevel@tonic-gate config_descr->wTotalLength, config_descr->bNumInterfaces,
17117c478bd9Sstevel@tonic-gate config_descr->bConfigurationValue,
17127c478bd9Sstevel@tonic-gate config_descr->bmAttributes, config_descr->bMaxPower);
17137c478bd9Sstevel@tonic-gate if ((config->cfg_n_if > 0) || (config->cfg_n_cvs > 0)) {
17147c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17157c478bd9Sstevel@tonic-gate "usb_cfg_data_t shows max if=%d "
17167c478bd9Sstevel@tonic-gate "and %d cv descr(s).",
17177c478bd9Sstevel@tonic-gate config->cfg_n_if - 1, config->cfg_n_cvs);
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate
17207c478bd9Sstevel@tonic-gate for (which_if = 0; which_if < config->cfg_n_if;
17217c478bd9Sstevel@tonic-gate which_if++) {
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) {
17247c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level,
1725112116d8Sfb dump_mask, " ");
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17287c478bd9Sstevel@tonic-gate " interface #%d (0x%p)",
1729112116d8Sfb which_if, (void *)&config->cfg_if[which_if]);
17307c478bd9Sstevel@tonic-gate usba_dump_if(&config->cfg_if[which_if],
17317c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate
17347c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < config->cfg_n_cvs; which_cv++) {
17357c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17367c478bd9Sstevel@tonic-gate " config cv descriptor %d (Address=0x%p)",
1737112116d8Sfb which_cv, (void *)&config->cfg_cvs[which_cv]);
17387c478bd9Sstevel@tonic-gate usba_dump_cv(&config->cfg_cvs[which_cv],
17397c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 4);
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate
17437c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17447c478bd9Sstevel@tonic-gate "Returning dev_curr_cfg:0x%p, dev_curr_if:%d",
1745112116d8Sfb (void *)usb_reg->dev_curr_cfg, usb_reg->dev_curr_if);
17467c478bd9Sstevel@tonic-gate
17477c478bd9Sstevel@tonic-gate if (log_handle == NULL) {
17487c478bd9Sstevel@tonic-gate usb_free_log_hdl(dump_handle);
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate if (name_string != NULL) {
17517c478bd9Sstevel@tonic-gate kmem_free(name_string, name_string_size);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate kmem_free(string, USB_MAXSTRINGLEN);
17547c478bd9Sstevel@tonic-gate
17557c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate /*
17607c478bd9Sstevel@tonic-gate * usba_dump_if:
17617c478bd9Sstevel@tonic-gate * Dump an interface node and its branches.
17627c478bd9Sstevel@tonic-gate *
17637c478bd9Sstevel@tonic-gate * Arguments:
17647c478bd9Sstevel@tonic-gate * which_if - interface node to dump
17657c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle
17667c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log
17677c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log
17687c478bd9Sstevel@tonic-gate * string - temporary area used for processing
17697c478bd9Sstevel@tonic-gate *
17707c478bd9Sstevel@tonic-gate */
17717c478bd9Sstevel@tonic-gate static void
usba_dump_if(usb_if_data_t * which_if,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * string)17727c478bd9Sstevel@tonic-gate usba_dump_if(usb_if_data_t *which_if, usb_log_handle_t dump_handle,
17737c478bd9Sstevel@tonic-gate uint_t dump_level, uint_t dump_mask, char *string)
17747c478bd9Sstevel@tonic-gate {
17757c478bd9Sstevel@tonic-gate int which_alt; /* Number of alt being dumped */
17767c478bd9Sstevel@tonic-gate usb_alt_if_data_t *alt; /* Pointer to it. */
17777c478bd9Sstevel@tonic-gate usb_if_descr_t *if_descr; /* Pointer to its USB descr. */
17787c478bd9Sstevel@tonic-gate int which_ep; /* Endpoint counter. */
17797c478bd9Sstevel@tonic-gate int which_cv; /* C/V descr counter. */
17807c478bd9Sstevel@tonic-gate
17817c478bd9Sstevel@tonic-gate for (which_alt = 0; which_alt < which_if->if_n_alt; which_alt++) {
17827c478bd9Sstevel@tonic-gate alt = &which_if->if_alt[which_alt];
17837c478bd9Sstevel@tonic-gate if_descr = &alt->altif_descr;
17847c478bd9Sstevel@tonic-gate
17857c478bd9Sstevel@tonic-gate if (if_descr->bLength == 0) {
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate continue;
17887c478bd9Sstevel@tonic-gate }
17897c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) {
17907c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, " ");
17917c478bd9Sstevel@tonic-gate }
17927c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
1793112116d8Sfb "\tAlt #%d (0x%p)", which_alt, (void *)alt);
17947c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17957c478bd9Sstevel@tonic-gate "\tString descr=%s", alt->altif_str);
17967c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
17977c478bd9Sstevel@tonic-gate "\tif descr: len=%d type=%d if=%d alt=%d n_ept=%d "
17987c478bd9Sstevel@tonic-gate "cls=%d sub=%d proto=%d",
17997c478bd9Sstevel@tonic-gate if_descr->bLength,
18007c478bd9Sstevel@tonic-gate if_descr->bDescriptorType, if_descr->bInterfaceNumber,
18017c478bd9Sstevel@tonic-gate if_descr->bAlternateSetting, if_descr->bNumEndpoints,
18027c478bd9Sstevel@tonic-gate if_descr->bInterfaceClass, if_descr->bInterfaceSubClass,
18037c478bd9Sstevel@tonic-gate if_descr->bInterfaceProtocol);
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate if ((alt->altif_n_ep > 0) || (alt->altif_n_cvs > 0)) {
18067c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
18077c478bd9Sstevel@tonic-gate "\tusb_alt_if_data_t shows max ep=%d "
18087c478bd9Sstevel@tonic-gate "and %d cv descr(s).",
18097c478bd9Sstevel@tonic-gate alt->altif_n_ep - 1, alt->altif_n_cvs);
18107c478bd9Sstevel@tonic-gate }
18117c478bd9Sstevel@tonic-gate
18127c478bd9Sstevel@tonic-gate for (which_ep = 0; which_ep < alt->altif_n_ep;
18137c478bd9Sstevel@tonic-gate which_ep++) {
18147c478bd9Sstevel@tonic-gate if (alt->altif_ep[which_ep].ep_descr.bLength == 0) {
18157c478bd9Sstevel@tonic-gate
18167c478bd9Sstevel@tonic-gate continue;
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) {
18197c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level,
1820112116d8Sfb dump_mask, " ");
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate usba_dump_ep(which_ep, &alt->altif_ep[which_ep],
18237c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string);
18247c478bd9Sstevel@tonic-gate }
18257c478bd9Sstevel@tonic-gate
18267c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < alt->altif_n_cvs; which_cv++) {
18277c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) {
18287c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level,
1829112116d8Sfb dump_mask, " ");
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
18327c478bd9Sstevel@tonic-gate "\talt cv descriptor #%d (0x%p), size=%d",
1833112116d8Sfb which_cv, (void *)&alt->altif_cvs[which_cv],
18347c478bd9Sstevel@tonic-gate alt->altif_cvs[which_cv].cvs_buf_len);
18357c478bd9Sstevel@tonic-gate usba_dump_cv(&alt->altif_cvs[which_cv],
18367c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 2);
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate }
18407c478bd9Sstevel@tonic-gate
18417c478bd9Sstevel@tonic-gate
18427c478bd9Sstevel@tonic-gate /*
18437c478bd9Sstevel@tonic-gate * usba_dump_ep:
18447c478bd9Sstevel@tonic-gate * Dump an endpoint node and its branches.
18457c478bd9Sstevel@tonic-gate *
18467c478bd9Sstevel@tonic-gate * Arguments:
18477c478bd9Sstevel@tonic-gate * which_ep - index to display
18487c478bd9Sstevel@tonic-gate * ep - endpoint node to dump
18497c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle
18507c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log
18517c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log
18527c478bd9Sstevel@tonic-gate * string - temporary area used for processing
18537c478bd9Sstevel@tonic-gate *
18547c478bd9Sstevel@tonic-gate */
18557c478bd9Sstevel@tonic-gate static void
usba_dump_ep(uint_t which_ep,usb_ep_data_t * ep,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * string)18567c478bd9Sstevel@tonic-gate usba_dump_ep(uint_t which_ep, usb_ep_data_t *ep, usb_log_handle_t dump_handle,
1857993e3fafSRobert Mustacchi uint_t dump_level, uint_t dump_mask, char *string)
18587c478bd9Sstevel@tonic-gate {
18597c478bd9Sstevel@tonic-gate int which_cv;
18607c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep_descr = &ep->ep_descr;
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
18637c478bd9Sstevel@tonic-gate "\t endpoint[%d], epaddr=0x%x (0x%p)", which_ep,
1864112116d8Sfb ep_descr->bEndpointAddress, (void *)ep);
18657c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
18667c478bd9Sstevel@tonic-gate "\t len=%d type=%d attr=0x%x pktsize=%d interval=%d",
18677c478bd9Sstevel@tonic-gate ep_descr->bLength, ep_descr->bDescriptorType,
18687c478bd9Sstevel@tonic-gate ep_descr->bmAttributes, ep_descr->wMaxPacketSize,
18697c478bd9Sstevel@tonic-gate ep_descr->bInterval);
18707c478bd9Sstevel@tonic-gate if (ep->ep_n_cvs > 0) {
18717c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
18727c478bd9Sstevel@tonic-gate "\t usb_ep_data_t shows %d cv descr(s)", ep->ep_n_cvs);
18737c478bd9Sstevel@tonic-gate }
18747c478bd9Sstevel@tonic-gate
18757c478bd9Sstevel@tonic-gate for (which_cv = 0; which_cv < ep->ep_n_cvs; which_cv++) {
18767c478bd9Sstevel@tonic-gate if (dump_level == USB_LOG_L0) {
18777c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level,
1878112116d8Sfb dump_mask, " ");
18797c478bd9Sstevel@tonic-gate }
18807c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
18817c478bd9Sstevel@tonic-gate "\t endpoint cv descriptor %d (0x%p), size=%d",
1882112116d8Sfb which_cv, (void *)&ep->ep_cvs[which_cv],
18837c478bd9Sstevel@tonic-gate ep->ep_cvs[which_cv].cvs_buf_len);
18847c478bd9Sstevel@tonic-gate usba_dump_cv(&ep->ep_cvs[which_cv],
18857c478bd9Sstevel@tonic-gate dump_handle, dump_level, dump_mask, string, 3);
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate }
18887c478bd9Sstevel@tonic-gate
18897c478bd9Sstevel@tonic-gate
18907c478bd9Sstevel@tonic-gate /*
18917c478bd9Sstevel@tonic-gate * usba_dump_cv:
18927c478bd9Sstevel@tonic-gate * Dump a raw class or vendor specific descriptor.
18937c478bd9Sstevel@tonic-gate *
18947c478bd9Sstevel@tonic-gate * Arguments:
18957c478bd9Sstevel@tonic-gate * cv_node - pointer to the descriptor to dump
18967c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle
18977c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log
18987c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log
18997c478bd9Sstevel@tonic-gate * string - temporary area used for processing
19007c478bd9Sstevel@tonic-gate * indent - number of tabs to indent output
19017c478bd9Sstevel@tonic-gate *
19027c478bd9Sstevel@tonic-gate */
19037c478bd9Sstevel@tonic-gate static void
usba_dump_cv(usb_cvs_data_t * cv_node,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * string,int indent)19047c478bd9Sstevel@tonic-gate usba_dump_cv(usb_cvs_data_t *cv_node, usb_log_handle_t dump_handle,
19057c478bd9Sstevel@tonic-gate uint_t dump_level, uint_t dump_mask, char *string, int indent)
19067c478bd9Sstevel@tonic-gate {
19077c478bd9Sstevel@tonic-gate if (cv_node) {
19087c478bd9Sstevel@tonic-gate usba_dump_bin(cv_node->cvs_buf, cv_node->cvs_buf_len, indent,
1909112116d8Sfb dump_handle, dump_level, dump_mask, string,
1910112116d8Sfb USB_MAXSTRINGLEN);
19117c478bd9Sstevel@tonic-gate }
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate /*
19167c478bd9Sstevel@tonic-gate * usba_dump_bin:
19177c478bd9Sstevel@tonic-gate * Generic byte dump function.
19187c478bd9Sstevel@tonic-gate *
19197c478bd9Sstevel@tonic-gate * Arguments:
19207c478bd9Sstevel@tonic-gate * data - pointer to the data to dump
19217c478bd9Sstevel@tonic-gate * max_bytes - amount of data to dump
19227c478bd9Sstevel@tonic-gate * indent - number of indentation levels
19237c478bd9Sstevel@tonic-gate * dump_handle - write data through this log handle
19247c478bd9Sstevel@tonic-gate * dump_level - level passed to usb_log
19257c478bd9Sstevel@tonic-gate * dump_mask - mask passed to usb_log
19267c478bd9Sstevel@tonic-gate * buffer - temporary area used for processing
19277c478bd9Sstevel@tonic-gate * bufferlen - size of the temporary string area
19287c478bd9Sstevel@tonic-gate *
19297c478bd9Sstevel@tonic-gate */
19307c478bd9Sstevel@tonic-gate static void
usba_dump_bin(uint8_t * data,int max_bytes,int indent,usb_log_handle_t dump_handle,uint_t dump_level,uint_t dump_mask,char * buffer,int bufferlen)19317c478bd9Sstevel@tonic-gate usba_dump_bin(uint8_t *data, int max_bytes, int indent,
19327c478bd9Sstevel@tonic-gate usb_log_handle_t dump_handle, uint_t dump_level, uint_t dump_mask,
19337c478bd9Sstevel@tonic-gate char *buffer, int bufferlen)
19347c478bd9Sstevel@tonic-gate {
19357c478bd9Sstevel@tonic-gate int i;
19367c478bd9Sstevel@tonic-gate int bufoffset = 0;
19377c478bd9Sstevel@tonic-gate int nexthere;
19387c478bd9Sstevel@tonic-gate
19397c478bd9Sstevel@tonic-gate if ((indent * SPACES_PER_INDENT) >
19407c478bd9Sstevel@tonic-gate (bufferlen - (BINDUMP_BYTES_PER_LINE * 3))) {
19417c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
19427c478bd9Sstevel@tonic-gate "Offset to usb_dump_bin must be %d or less. "
19437c478bd9Sstevel@tonic-gate "Setting to 0.\n",
19447c478bd9Sstevel@tonic-gate (bufferlen - (BINDUMP_BYTES_PER_LINE * 3)));
19457c478bd9Sstevel@tonic-gate indent = 0;
19467c478bd9Sstevel@tonic-gate }
19477c478bd9Sstevel@tonic-gate
19487c478bd9Sstevel@tonic-gate /* Assume a tab is 2 four-space units. */
19497c478bd9Sstevel@tonic-gate for (i = 0; i < indent/2; i++) {
1950112116d8Sfb buffer[bufoffset] = '\t';
1951112116d8Sfb bufoffset++;
19527c478bd9Sstevel@tonic-gate }
19537c478bd9Sstevel@tonic-gate
19547c478bd9Sstevel@tonic-gate if (indent % 2) {
19557c478bd9Sstevel@tonic-gate (void) strcpy(&buffer[bufoffset], INDENT_SPACE_STR);
19567c478bd9Sstevel@tonic-gate bufoffset += SPACES_PER_INDENT;
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate
19597c478bd9Sstevel@tonic-gate i = 0; /* Num dumped bytes put on this line. */
19607c478bd9Sstevel@tonic-gate nexthere = bufoffset;
19617c478bd9Sstevel@tonic-gate while (i < max_bytes) {
19627c478bd9Sstevel@tonic-gate (void) sprintf(&buffer[nexthere], "%2x ", *data++);
19637c478bd9Sstevel@tonic-gate nexthere += 3;
19647c478bd9Sstevel@tonic-gate i++;
19657c478bd9Sstevel@tonic-gate if (!(i % BINDUMP_BYTES_PER_LINE)) {
19667c478bd9Sstevel@tonic-gate buffer[nexthere] = '\0';
19677c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask,
19687c478bd9Sstevel@tonic-gate buffer);
19697c478bd9Sstevel@tonic-gate nexthere = bufoffset;
19707c478bd9Sstevel@tonic-gate }
19717c478bd9Sstevel@tonic-gate }
19727c478bd9Sstevel@tonic-gate
19737c478bd9Sstevel@tonic-gate if (nexthere > bufoffset) {
19747c478bd9Sstevel@tonic-gate buffer[nexthere] = '\0';
19757c478bd9Sstevel@tonic-gate (void) usb_log(dump_handle, dump_level, dump_mask, buffer);
19767c478bd9Sstevel@tonic-gate }
19777c478bd9Sstevel@tonic-gate }
1978993e3fafSRobert Mustacchi
1979993e3fafSRobert Mustacchi /*
1980993e3fafSRobert Mustacchi * usb_ep_xdescr_fill:
1981993e3fafSRobert Mustacchi *
1982993e3fafSRobert Mustacchi * Fills in the extended endpoint descriptor based on data from the
1983993e3fafSRobert Mustacchi * configuration tree.
1984993e3fafSRobert Mustacchi *
1985993e3fafSRobert Mustacchi * Arguments:
1986993e3fafSRobert Mustacchi * version - Should be USB_EP_XDESCR_CURRENT_VERSION
1987993e3fafSRobert Mustacchi * dip - devinfo pointer
1988993e3fafSRobert Mustacchi * ep_data - endpoint data pointer
1989993e3fafSRobert Mustacchi * ep_xdesc - An extended descriptor structure, filled upon
1990993e3fafSRobert Mustacchi * successful completion.
1991993e3fafSRobert Mustacchi *
1992993e3fafSRobert Mustacchi * Return values:
1993993e3fafSRobert Mustacchi * USB_SUCCESS - filling data succeeded
1994993e3fafSRobert Mustacchi * USB_INVALID_ARGS - invalid arguments
1995993e3fafSRobert Mustacchi */
1996993e3fafSRobert Mustacchi int
usb_ep_xdescr_fill(uint_t version,dev_info_t * dip,usb_ep_data_t * ep_data,usb_ep_xdescr_t * ep_xdescr)1997993e3fafSRobert Mustacchi usb_ep_xdescr_fill(uint_t version, dev_info_t *dip, usb_ep_data_t *ep_data,
1998993e3fafSRobert Mustacchi usb_ep_xdescr_t *ep_xdescr)
1999993e3fafSRobert Mustacchi {
2000993e3fafSRobert Mustacchi if (version != USB_EP_XDESCR_VERSION_ONE) {
2001993e3fafSRobert Mustacchi
2002993e3fafSRobert Mustacchi return (USB_INVALID_ARGS);
2003993e3fafSRobert Mustacchi }
2004993e3fafSRobert Mustacchi
2005993e3fafSRobert Mustacchi if (dip == NULL || ep_data == NULL || ep_xdescr == NULL) {
2006993e3fafSRobert Mustacchi
2007993e3fafSRobert Mustacchi return (USB_INVALID_ARGS);
2008993e3fafSRobert Mustacchi }
2009993e3fafSRobert Mustacchi
2010993e3fafSRobert Mustacchi bzero(ep_xdescr, sizeof (usb_ep_xdescr_t));
2011993e3fafSRobert Mustacchi ep_xdescr->uex_version = version;
2012993e3fafSRobert Mustacchi ep_xdescr->uex_ep = ep_data->ep_descr;
2013993e3fafSRobert Mustacchi if (ep_data->ep_ss_valid == B_TRUE) {
2014993e3fafSRobert Mustacchi ep_xdescr->uex_flags |= USB_EP_XFLAGS_SS_COMP;
2015993e3fafSRobert Mustacchi ep_xdescr->uex_ep_ss = ep_data->ep_ss_comp;
2016993e3fafSRobert Mustacchi }
2017993e3fafSRobert Mustacchi
2018993e3fafSRobert Mustacchi return (USB_SUCCESS);
2019993e3fafSRobert Mustacchi }
2020