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;
1099