1*0d2006e4SRobert Mustacchi /*
2*0d2006e4SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*0d2006e4SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*0d2006e4SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*0d2006e4SRobert Mustacchi  * 1.0 of the CDDL.
6*0d2006e4SRobert Mustacchi  *
7*0d2006e4SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*0d2006e4SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*0d2006e4SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*0d2006e4SRobert Mustacchi  */
11*0d2006e4SRobert Mustacchi 
12*0d2006e4SRobert Mustacchi /*
13*0d2006e4SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
14*0d2006e4SRobert Mustacchi  */
15*0d2006e4SRobert Mustacchi 
16*0d2006e4SRobert Mustacchi /*
17*0d2006e4SRobert Mustacchi  * Routines to access, parse, and manage the USB Binary Object Store
18*0d2006e4SRobert Mustacchi  */
19*0d2006e4SRobert Mustacchi 
20*0d2006e4SRobert Mustacchi #define	USBA_FRAMEWORK
21*0d2006e4SRobert Mustacchi #include <sys/usb/usba/usba_impl.h>
22*0d2006e4SRobert Mustacchi #include <sys/strsun.h>
23*0d2006e4SRobert Mustacchi #include <sys/sysmacros.h>
24*0d2006e4SRobert Mustacchi 
25*0d2006e4SRobert Mustacchi static size_t
usba_bos_parse_bos_descr(const uchar_t * buf,size_t buflen,usb_bos_descr_t * bosp,size_t rlen)26*0d2006e4SRobert Mustacchi usba_bos_parse_bos_descr(const uchar_t *buf, size_t buflen,
27*0d2006e4SRobert Mustacchi     usb_bos_descr_t *bosp, size_t rlen)
28*0d2006e4SRobert Mustacchi {
29*0d2006e4SRobert Mustacchi 	if (buf == NULL || bosp == NULL || buflen < USB_BOS_PACKED_SIZE ||
30*0d2006e4SRobert Mustacchi 	    buf[1] != USB_DESCR_TYPE_BOS) {
31*0d2006e4SRobert Mustacchi 		return (USB_PARSE_ERROR);
32*0d2006e4SRobert Mustacchi 	}
33*0d2006e4SRobert Mustacchi 
34*0d2006e4SRobert Mustacchi 	return (usb_parse_data("ccsc", buf, buflen, bosp, rlen));
35*0d2006e4SRobert Mustacchi }
36*0d2006e4SRobert Mustacchi 
37*0d2006e4SRobert Mustacchi static boolean_t
usba_bos_parse_usb2ext(const uchar_t * buf,size_t buflen,usb_bos_t * bosp)38*0d2006e4SRobert Mustacchi usba_bos_parse_usb2ext(const uchar_t *buf, size_t buflen, usb_bos_t *bosp)
39*0d2006e4SRobert Mustacchi {
40*0d2006e4SRobert Mustacchi 	size_t len;
41*0d2006e4SRobert Mustacchi 
42*0d2006e4SRobert Mustacchi 	if (buflen != USB_BOS_USB2EXT_PACKED_SIZE) {
43*0d2006e4SRobert Mustacchi 		return (B_FALSE);
44*0d2006e4SRobert Mustacchi 	}
45*0d2006e4SRobert Mustacchi 
46*0d2006e4SRobert Mustacchi 	len = usb_parse_data("cccl", buf, buflen, &bosp->ubos_caps.ubos_usb2,
47*0d2006e4SRobert Mustacchi 	    sizeof (usb_bos_usb2ext_t));
48*0d2006e4SRobert Mustacchi 	return (len == sizeof (usb_bos_usb2ext_t));
49*0d2006e4SRobert Mustacchi }
50*0d2006e4SRobert Mustacchi 
51*0d2006e4SRobert Mustacchi static boolean_t
usba_bos_parse_superspeed(const uchar_t * buf,size_t buflen,usb_bos_t * bosp)52*0d2006e4SRobert Mustacchi usba_bos_parse_superspeed(const uchar_t *buf, size_t buflen, usb_bos_t *bosp)
53*0d2006e4SRobert Mustacchi {
54*0d2006e4SRobert Mustacchi 	size_t len;
55*0d2006e4SRobert Mustacchi 
56*0d2006e4SRobert Mustacchi 	if (buflen != USB_BOS_SSUSB_PACKED_SIZE) {
57*0d2006e4SRobert Mustacchi 		return (B_FALSE);
58*0d2006e4SRobert Mustacchi 	}
59*0d2006e4SRobert Mustacchi 
60*0d2006e4SRobert Mustacchi 	len = usb_parse_data("ccccsccs", buf, buflen,
61*0d2006e4SRobert Mustacchi 	    &bosp->ubos_caps.ubos_ssusb, sizeof (usb_bos_ssusb_t));
62*0d2006e4SRobert Mustacchi 	return (len == sizeof (usb_bos_ssusb_t));
63*0d2006e4SRobert Mustacchi }
64*0d2006e4SRobert Mustacchi 
65*0d2006e4SRobert Mustacchi static boolean_t
usba_bos_parse_container(const uchar_t * buf,size_t buflen,usb_bos_t * bosp)66*0d2006e4SRobert Mustacchi usba_bos_parse_container(const uchar_t *buf, size_t buflen, usb_bos_t *bosp)
67*0d2006e4SRobert Mustacchi {
68*0d2006e4SRobert Mustacchi 	size_t len;
69*0d2006e4SRobert Mustacchi 
70*0d2006e4SRobert Mustacchi 	if (buflen != USB_BOS_CONTAINER_PACKED_SIZE) {
71*0d2006e4SRobert Mustacchi 		return (B_FALSE);
72*0d2006e4SRobert Mustacchi 	}
73*0d2006e4SRobert Mustacchi 
74*0d2006e4SRobert Mustacchi 	len = usb_parse_data("cccc16c", buf, buflen,
75*0d2006e4SRobert Mustacchi 	    &bosp->ubos_caps.ubos_container, sizeof (usb_bos_container_t));
76*0d2006e4SRobert Mustacchi 	return (len == sizeof (usb_bos_container_t));
77*0d2006e4SRobert Mustacchi }
78*0d2006e4SRobert Mustacchi 
79*0d2006e4SRobert Mustacchi static boolean_t
usba_bos_parse_precision_time(const uchar_t * buf,size_t buflen,usb_bos_t * bosp)80*0d2006e4SRobert Mustacchi usba_bos_parse_precision_time(const uchar_t *buf, size_t buflen,
81*0d2006e4SRobert Mustacchi     usb_bos_t *bosp)
82*0d2006e4SRobert Mustacchi {
83*0d2006e4SRobert Mustacchi 	size_t len;
84*0d2006e4SRobert Mustacchi 
85*0d2006e4SRobert Mustacchi 	if (buflen != USB_BOS_PRECISION_TIME_PACKED_SIZE) {
86*0d2006e4SRobert Mustacchi 		return (B_FALSE);
87*0d2006e4SRobert Mustacchi 	}
88*0d2006e4SRobert Mustacchi 
89*0d2006e4SRobert Mustacchi 	len = usb_parse_data("ccc", buf, buflen, &bosp->ubos_caps.ubos_time,
90*0d2006e4SRobert Mustacchi 	    sizeof (usb_bos_precision_time_t));
91*0d2006e4SRobert Mustacchi 	/*
92*0d2006e4SRobert Mustacchi 	 * The actual size of this structure will usually be rounded up to four
93*0d2006e4SRobert Mustacchi 	 * bytes by the compiler, therefore we need to compare against the
94*0d2006e4SRobert Mustacchi 	 * packed size.
95*0d2006e4SRobert Mustacchi 	 */
96*0d2006e4SRobert Mustacchi 	return (len == USB_BOS_PRECISION_TIME_PACKED_SIZE);
97*0d2006e4SRobert Mustacchi }
98*0d2006e4SRobert Mustacchi 
99*0d2006e4SRobert Mustacchi /*
100*0d2006e4SRobert Mustacchi  * Validate that the BOS looks reasonable. This means the following:
101*0d2006e4SRobert Mustacchi  *
102*0d2006e4SRobert Mustacchi  * - We read the whole length of the descriptor
103*0d2006e4SRobert Mustacchi  * - The total number of capabilities doesn't exceed the expected value
104*0d2006e4SRobert Mustacchi  * - The length of each device capabilities fits within our expected range
105*0d2006e4SRobert Mustacchi  *
106*0d2006e4SRobert Mustacchi  * After we finish that up, go through and save all of the valid BOS
107*0d2006e4SRobert Mustacchi  * descriptors, unpacking the ones that we actually understand.
108*0d2006e4SRobert Mustacchi  */
109*0d2006e4SRobert Mustacchi static boolean_t
usba_bos_save(usba_device_t * ud,const mblk_t * mp,usb_bos_descr_t * bdesc)110*0d2006e4SRobert Mustacchi usba_bos_save(usba_device_t *ud, const mblk_t *mp, usb_bos_descr_t *bdesc)
111*0d2006e4SRobert Mustacchi {
112*0d2006e4SRobert Mustacchi 	size_t len = MBLKL(mp);
113*0d2006e4SRobert Mustacchi 	const uchar_t *buf = mp->b_rptr;
114*0d2006e4SRobert Mustacchi 	uint_t ncaps, nalloc;
115*0d2006e4SRobert Mustacchi 	usb_bos_t *bos;
116*0d2006e4SRobert Mustacchi 
117*0d2006e4SRobert Mustacchi 	if (bdesc->bLength != USB_BOS_PACKED_SIZE ||
118*0d2006e4SRobert Mustacchi 	    bdesc->bNumDeviceCaps == 0 || len < USB_BOS_PACKED_SIZE ||
119*0d2006e4SRobert Mustacchi 	    len < bdesc->wTotalLength) {
120*0d2006e4SRobert Mustacchi 		return (B_FALSE);
121*0d2006e4SRobert Mustacchi 	}
122*0d2006e4SRobert Mustacchi 
123*0d2006e4SRobert Mustacchi 	len = MIN(len, bdesc->wTotalLength);
124*0d2006e4SRobert Mustacchi 	buf += USB_BOS_PACKED_SIZE;
125*0d2006e4SRobert Mustacchi 	len -= USB_BOS_PACKED_SIZE;
126*0d2006e4SRobert Mustacchi 
127*0d2006e4SRobert Mustacchi 	if (len < USB_DEV_CAP_PACKED_SIZE) {
128*0d2006e4SRobert Mustacchi 		return (B_FALSE);
129*0d2006e4SRobert Mustacchi 	}
130*0d2006e4SRobert Mustacchi 
131*0d2006e4SRobert Mustacchi 	ncaps = 0;
132*0d2006e4SRobert Mustacchi 	while (len > 0) {
133*0d2006e4SRobert Mustacchi 		usb_dev_cap_descr_t dev;
134*0d2006e4SRobert Mustacchi 
135*0d2006e4SRobert Mustacchi 		if (usb_parse_data("ccc", buf, len, &dev, sizeof (dev)) !=
136*0d2006e4SRobert Mustacchi 		    USB_DEV_CAP_PACKED_SIZE) {
137*0d2006e4SRobert Mustacchi 			return (B_FALSE);
138*0d2006e4SRobert Mustacchi 		}
139*0d2006e4SRobert Mustacchi 
140*0d2006e4SRobert Mustacchi 		if (dev.bDescriptorType != USB_DESCR_TYPE_DEV_CAPABILITY ||
141*0d2006e4SRobert Mustacchi 		    dev.bLength > len) {
142*0d2006e4SRobert Mustacchi 			return (B_FALSE);
143*0d2006e4SRobert Mustacchi 		}
144*0d2006e4SRobert Mustacchi 
145*0d2006e4SRobert Mustacchi 		ncaps++;
146*0d2006e4SRobert Mustacchi 		len -= dev.bLength;
147*0d2006e4SRobert Mustacchi 		buf += dev.bLength;
148*0d2006e4SRobert Mustacchi 	}
149*0d2006e4SRobert Mustacchi 
150*0d2006e4SRobert Mustacchi 	if (ncaps != bdesc->bNumDeviceCaps) {
151*0d2006e4SRobert Mustacchi 		return (B_FALSE);
152*0d2006e4SRobert Mustacchi 	}
153*0d2006e4SRobert Mustacchi 
154*0d2006e4SRobert Mustacchi 	nalloc = ncaps;
155*0d2006e4SRobert Mustacchi 	bos = kmem_zalloc(sizeof (usb_bos_t) * nalloc, KM_SLEEP);
156*0d2006e4SRobert Mustacchi 	buf = mp->b_rptr + USB_BOS_PACKED_SIZE;
157*0d2006e4SRobert Mustacchi 	len = MIN(MBLKL(mp), bdesc->wTotalLength) - USB_BOS_PACKED_SIZE;
158*0d2006e4SRobert Mustacchi 	ncaps = 0;
159*0d2006e4SRobert Mustacchi 	while (len > 0) {
160*0d2006e4SRobert Mustacchi 		usb_dev_cap_descr_t dev;
161*0d2006e4SRobert Mustacchi 		boolean_t valid;
162*0d2006e4SRobert Mustacchi 
163*0d2006e4SRobert Mustacchi 		if (usb_parse_data("ccc", buf, len, &dev, sizeof (dev)) !=
164*0d2006e4SRobert Mustacchi 		    USB_DEV_CAP_PACKED_SIZE) {
165*0d2006e4SRobert Mustacchi 			goto fail;
166*0d2006e4SRobert Mustacchi 		}
167*0d2006e4SRobert Mustacchi 
168*0d2006e4SRobert Mustacchi 		bos[ncaps].ubos_length = dev.bLength;
169*0d2006e4SRobert Mustacchi 		bos[ncaps].ubos_type = dev.bDevCapabilityType;
170*0d2006e4SRobert Mustacchi 
171*0d2006e4SRobert Mustacchi 		valid = B_FALSE;
172*0d2006e4SRobert Mustacchi 		switch (dev.bDevCapabilityType) {
173*0d2006e4SRobert Mustacchi 		case USB_BOS_TYPE_USB2_EXT:
174*0d2006e4SRobert Mustacchi 			valid = usba_bos_parse_usb2ext(buf, dev.bLength,
175*0d2006e4SRobert Mustacchi 			    &bos[ncaps]);
176*0d2006e4SRobert Mustacchi 			break;
177*0d2006e4SRobert Mustacchi 		case USB_BOS_TYPE_SUPERSPEED:
178*0d2006e4SRobert Mustacchi 			valid = usba_bos_parse_superspeed(buf, dev.bLength,
179*0d2006e4SRobert Mustacchi 			    &bos[ncaps]);
180*0d2006e4SRobert Mustacchi 			break;
181*0d2006e4SRobert Mustacchi 		case USB_BOS_TYPE_CONTAINER:
182*0d2006e4SRobert Mustacchi 			valid = usba_bos_parse_container(buf, dev.bLength,
183*0d2006e4SRobert Mustacchi 			    &bos[ncaps]);
184*0d2006e4SRobert Mustacchi 			break;
185*0d2006e4SRobert Mustacchi 		case USB_BOS_TYPE_PRECISION_TIME:
186*0d2006e4SRobert Mustacchi 			valid = usba_bos_parse_precision_time(buf, dev.bLength,
187*0d2006e4SRobert Mustacchi 			    &bos[ncaps]);
188*0d2006e4SRobert Mustacchi 			break;
189*0d2006e4SRobert Mustacchi 		default:
190*0d2006e4SRobert Mustacchi 			/*
191*0d2006e4SRobert Mustacchi 			 * Override the type to one that we know isn't used to
192*0d2006e4SRobert Mustacchi 			 * indicate that the caller can't rely on the type
193*0d2006e4SRobert Mustacchi 			 * that's present here.
194*0d2006e4SRobert Mustacchi 			 */
195*0d2006e4SRobert Mustacchi 			bos[ncaps].ubos_type = USB_BOS_TYPE_INVALID;
196*0d2006e4SRobert Mustacchi 			bcopy(buf, bos[ncaps].ubos_caps.ubos_raw, dev.bLength);
197*0d2006e4SRobert Mustacchi 			valid = B_TRUE;
198*0d2006e4SRobert Mustacchi 			break;
199*0d2006e4SRobert Mustacchi 		}
200*0d2006e4SRobert Mustacchi 
201*0d2006e4SRobert Mustacchi 		if (valid) {
202*0d2006e4SRobert Mustacchi 			ncaps++;
203*0d2006e4SRobert Mustacchi 		} else {
204*0d2006e4SRobert Mustacchi 			bos[ncaps].ubos_length = 0;
205*0d2006e4SRobert Mustacchi 			bos[ncaps].ubos_type = USB_BOS_TYPE_INVALID;
206*0d2006e4SRobert Mustacchi 			bzero(bos[ncaps].ubos_caps.ubos_raw,
207*0d2006e4SRobert Mustacchi 			    sizeof (bos[ncaps].ubos_caps.ubos_raw));
208*0d2006e4SRobert Mustacchi 		}
209*0d2006e4SRobert Mustacchi 		len -= dev.bLength;
210*0d2006e4SRobert Mustacchi 		buf += dev.bLength;
211*0d2006e4SRobert Mustacchi 	}
212*0d2006e4SRobert Mustacchi 
213*0d2006e4SRobert Mustacchi 	ud->usb_bos_nalloc = nalloc;
214*0d2006e4SRobert Mustacchi 	ud->usb_bos_nents = ncaps;
215*0d2006e4SRobert Mustacchi 	ud->usb_bos = bos;
216*0d2006e4SRobert Mustacchi 
217*0d2006e4SRobert Mustacchi 	return (B_TRUE);
218*0d2006e4SRobert Mustacchi 
219*0d2006e4SRobert Mustacchi fail:
220*0d2006e4SRobert Mustacchi 	kmem_free(bos, sizeof (usb_bos_t) * nalloc);
221*0d2006e4SRobert Mustacchi 	return (B_FALSE);
222*0d2006e4SRobert Mustacchi }
223*0d2006e4SRobert Mustacchi 
224*0d2006e4SRobert Mustacchi /*
225*0d2006e4SRobert Mustacchi  * Read the Binary Object Store (BOS) data from the device and attempt to parse
226*0d2006e4SRobert Mustacchi  * it. Do not fail to attach the device if we cannot get all of the information
227*0d2006e4SRobert Mustacchi  * at this time. While certain aspects of the BOS are required for Windows,
228*0d2006e4SRobert Mustacchi  * which suggests that we could actually rely on it, we haven't historically.
229*0d2006e4SRobert Mustacchi  */
230*0d2006e4SRobert Mustacchi void
usba_get_binary_object_store(dev_info_t * dip,usba_device_t * ud)231*0d2006e4SRobert Mustacchi usba_get_binary_object_store(dev_info_t *dip, usba_device_t *ud)
232*0d2006e4SRobert Mustacchi {
233*0d2006e4SRobert Mustacchi 	int			rval;
234*0d2006e4SRobert Mustacchi 	mblk_t			*mp = NULL;
235*0d2006e4SRobert Mustacchi 	usb_cr_t		completion_reason;
236*0d2006e4SRobert Mustacchi 	usb_cb_flags_t		cb_flags;
237*0d2006e4SRobert Mustacchi 	usb_pipe_handle_t	ph;
238*0d2006e4SRobert Mustacchi 	size_t			size;
239*0d2006e4SRobert Mustacchi 	usb_bos_descr_t		bos;
240*0d2006e4SRobert Mustacchi 
241*0d2006e4SRobert Mustacchi 	/*
242*0d2006e4SRobert Mustacchi 	 * The BOS is only supported on USB 3.x devices. Therefore if the bcdUSB
243*0d2006e4SRobert Mustacchi 	 * is greater than USB 2.0, we can check this. Note, USB 3.x devices
244*0d2006e4SRobert Mustacchi 	 * that are linked on a USB device will report version 2.1 in the bcdUSB
245*0d2006e4SRobert Mustacchi 	 * field.
246*0d2006e4SRobert Mustacchi 	 */
247*0d2006e4SRobert Mustacchi 	if (ud->usb_dev_descr->bcdUSB <= 0x200) {
248*0d2006e4SRobert Mustacchi 		return;
249*0d2006e4SRobert Mustacchi 	}
250*0d2006e4SRobert Mustacchi 
251*0d2006e4SRobert Mustacchi 	ph = usba_get_dflt_pipe_handle(dip);
252*0d2006e4SRobert Mustacchi 
253*0d2006e4SRobert Mustacchi 	/*
254*0d2006e4SRobert Mustacchi 	 * First get just the BOS descriptor itself.
255*0d2006e4SRobert Mustacchi 	 */
256*0d2006e4SRobert Mustacchi 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
257*0d2006e4SRobert Mustacchi 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
258*0d2006e4SRobert Mustacchi 	    USB_REQ_GET_DESCR,			/* bRequest */
259*0d2006e4SRobert Mustacchi 	    (USB_DESCR_TYPE_BOS << 8),		/* wValue */
260*0d2006e4SRobert Mustacchi 	    0,					/* wIndex */
261*0d2006e4SRobert Mustacchi 	    USB_BOS_PACKED_SIZE,		/* wLength */
262*0d2006e4SRobert Mustacchi 	    &mp, USB_ATTRS_SHORT_XFER_OK,
263*0d2006e4SRobert Mustacchi 	    &completion_reason, &cb_flags, 0);
264*0d2006e4SRobert Mustacchi 
265*0d2006e4SRobert Mustacchi 	if (rval != USB_SUCCESS) {
266*0d2006e4SRobert Mustacchi 		return;
267*0d2006e4SRobert Mustacchi 	}
268*0d2006e4SRobert Mustacchi 
269*0d2006e4SRobert Mustacchi 	size = usba_bos_parse_bos_descr(mp->b_rptr, MBLKL(mp), &bos,
270*0d2006e4SRobert Mustacchi 	    sizeof (bos));
271*0d2006e4SRobert Mustacchi 	freemsg(mp);
272*0d2006e4SRobert Mustacchi 	mp = NULL;
273*0d2006e4SRobert Mustacchi 	if (size < USB_BOS_PACKED_SIZE) {
274*0d2006e4SRobert Mustacchi 		return;
275*0d2006e4SRobert Mustacchi 	}
276*0d2006e4SRobert Mustacchi 
277*0d2006e4SRobert Mustacchi 	/*
278*0d2006e4SRobert Mustacchi 	 * Check to see if there are any capabilities and if it's worth getting
279*0d2006e4SRobert Mustacchi 	 * the whole BOS.
280*0d2006e4SRobert Mustacchi 	 */
281*0d2006e4SRobert Mustacchi 	if (bos.bLength != USB_BOS_PACKED_SIZE || bos.bNumDeviceCaps == 0) {
282*0d2006e4SRobert Mustacchi 		return;
283*0d2006e4SRobert Mustacchi 	}
284*0d2006e4SRobert Mustacchi 
285*0d2006e4SRobert Mustacchi 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
286*0d2006e4SRobert Mustacchi 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
287*0d2006e4SRobert Mustacchi 	    USB_REQ_GET_DESCR,			/* bRequest */
288*0d2006e4SRobert Mustacchi 	    (USB_DESCR_TYPE_BOS << 8),		/* wValue */
289*0d2006e4SRobert Mustacchi 	    0,					/* wIndex */
290*0d2006e4SRobert Mustacchi 	    bos.wTotalLength,			/* wLength */
291*0d2006e4SRobert Mustacchi 	    &mp, USB_ATTRS_SHORT_XFER_OK,
292*0d2006e4SRobert Mustacchi 	    &completion_reason, &cb_flags, 0);
293*0d2006e4SRobert Mustacchi 
294*0d2006e4SRobert Mustacchi 	if (rval != USB_SUCCESS) {
295*0d2006e4SRobert Mustacchi 		return;
296*0d2006e4SRobert Mustacchi 	}
297*0d2006e4SRobert Mustacchi 
298*0d2006e4SRobert Mustacchi 	size = usba_bos_parse_bos_descr(mp->b_rptr, MBLKL(mp), &bos,
299*0d2006e4SRobert Mustacchi 	    sizeof (bos));
300*0d2006e4SRobert Mustacchi 	if (size < USB_BOS_PACKED_SIZE) {
301*0d2006e4SRobert Mustacchi 		freemsg(mp);
302*0d2006e4SRobert Mustacchi 		return;
303*0d2006e4SRobert Mustacchi 	}
304*0d2006e4SRobert Mustacchi 
305*0d2006e4SRobert Mustacchi 	if (!usba_bos_save(ud, mp, &bos)) {
306*0d2006e4SRobert Mustacchi 		freemsg(mp);
307*0d2006e4SRobert Mustacchi 		return;
308*0d2006e4SRobert Mustacchi 	}
309*0d2006e4SRobert Mustacchi 
310*0d2006e4SRobert Mustacchi 	ud->usb_bos_mp = mp;
311*0d2006e4SRobert Mustacchi }
312*0d2006e4SRobert Mustacchi 
313*0d2006e4SRobert Mustacchi static void
usba_add_superspeed_props(dev_info_t * dip,usb_bos_ssusb_t * ssusb)314*0d2006e4SRobert Mustacchi usba_add_superspeed_props(dev_info_t *dip, usb_bos_ssusb_t *ssusb)
315*0d2006e4SRobert Mustacchi {
316*0d2006e4SRobert Mustacchi 	char *supported[4];
317*0d2006e4SRobert Mustacchi 	uint_t nsup = 0;
318*0d2006e4SRobert Mustacchi 	char *min;
319*0d2006e4SRobert Mustacchi 
320*0d2006e4SRobert Mustacchi 	if (ssusb->wSpeedsSupported & USB_BOS_SSUSB_SPEED_LOW) {
321*0d2006e4SRobert Mustacchi 		supported[nsup++] = "low-speed";
322*0d2006e4SRobert Mustacchi 	}
323*0d2006e4SRobert Mustacchi 
324*0d2006e4SRobert Mustacchi 	if (ssusb->wSpeedsSupported & USB_BOS_SSUSB_SPEED_FULL) {
325*0d2006e4SRobert Mustacchi 		supported[nsup++] = "full-speed";
326*0d2006e4SRobert Mustacchi 	}
327*0d2006e4SRobert Mustacchi 
328*0d2006e4SRobert Mustacchi 	if (ssusb->wSpeedsSupported & USB_BOS_SSUSB_SPEED_HIGH) {
329*0d2006e4SRobert Mustacchi 		supported[nsup++] = "high-speed";
330*0d2006e4SRobert Mustacchi 	}
331*0d2006e4SRobert Mustacchi 
332*0d2006e4SRobert Mustacchi 	if (ssusb->wSpeedsSupported & USB_BOS_SSUSB_SPEED_SUPER) {
333*0d2006e4SRobert Mustacchi 		supported[nsup++] = "super-speed";
334*0d2006e4SRobert Mustacchi 	}
335*0d2006e4SRobert Mustacchi 
336*0d2006e4SRobert Mustacchi 	if (nsup != 0 && ndi_prop_update_string_array(DDI_DEV_T_NONE, dip,
337*0d2006e4SRobert Mustacchi 	    "usb-supported-speeds", supported, nsup) != DDI_PROP_SUCCESS) {
338*0d2006e4SRobert Mustacchi 		USB_DPRINTF_L2(DPRINT_MASK_USBA, NULL, "failed to add "
339*0d2006e4SRobert Mustacchi 		    "usb-supported-speeds property");
340*0d2006e4SRobert Mustacchi 	}
341*0d2006e4SRobert Mustacchi 
342*0d2006e4SRobert Mustacchi 	switch (ssusb->bFunctionalitySupport) {
343*0d2006e4SRobert Mustacchi 	case 0:
344*0d2006e4SRobert Mustacchi 		min = "low-speed";
345*0d2006e4SRobert Mustacchi 		break;
346*0d2006e4SRobert Mustacchi 	case 1:
347*0d2006e4SRobert Mustacchi 		min = "full-speed";
348*0d2006e4SRobert Mustacchi 		break;
349*0d2006e4SRobert Mustacchi 	case 2:
350*0d2006e4SRobert Mustacchi 		min = "high-speed";
351*0d2006e4SRobert Mustacchi 		break;
352*0d2006e4SRobert Mustacchi 	case 3:
353*0d2006e4SRobert Mustacchi 		min = "super-speed";
354*0d2006e4SRobert Mustacchi 		break;
355*0d2006e4SRobert Mustacchi 	default:
356*0d2006e4SRobert Mustacchi 		min = NULL;
357*0d2006e4SRobert Mustacchi 	}
358*0d2006e4SRobert Mustacchi 
359*0d2006e4SRobert Mustacchi 	if (min != NULL && ndi_prop_update_string(DDI_DEV_T_NONE, dip,
360*0d2006e4SRobert Mustacchi 	    "usb-minimum-speed", min) != DDI_PROP_SUCCESS) {
361*0d2006e4SRobert Mustacchi 		USB_DPRINTF_L2(DPRINT_MASK_USBA, NULL, "failed to add "
362*0d2006e4SRobert Mustacchi 		    "usb-minimum-speed property");
363*0d2006e4SRobert Mustacchi 	}
364*0d2006e4SRobert Mustacchi }
365*0d2006e4SRobert Mustacchi 
366*0d2006e4SRobert Mustacchi static void
usba_add_container_props(dev_info_t * dip,usb_bos_container_t * cp)367*0d2006e4SRobert Mustacchi usba_add_container_props(dev_info_t *dip, usb_bos_container_t *cp)
368*0d2006e4SRobert Mustacchi {
369*0d2006e4SRobert Mustacchi 	if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "usb-container-id",
370*0d2006e4SRobert Mustacchi 	    cp->ContainerId, sizeof (cp->ContainerId)) != DDI_PROP_SUCCESS) {
371*0d2006e4SRobert Mustacchi 		USB_DPRINTF_L2(DPRINT_MASK_USBA, NULL, "failed to add "
372*0d2006e4SRobert Mustacchi 		    "usb-container-id property");
373*0d2006e4SRobert Mustacchi 	}
374*0d2006e4SRobert Mustacchi }
375*0d2006e4SRobert Mustacchi 
376*0d2006e4SRobert Mustacchi void
usba_add_binary_object_store_props(dev_info_t * dip,usba_device_t * ud)377*0d2006e4SRobert Mustacchi usba_add_binary_object_store_props(dev_info_t *dip, usba_device_t *ud)
378*0d2006e4SRobert Mustacchi {
379*0d2006e4SRobert Mustacchi 	uint_t i;
380*0d2006e4SRobert Mustacchi 
381*0d2006e4SRobert Mustacchi 	if (ud->usb_bos == NULL) {
382*0d2006e4SRobert Mustacchi 		return;
383*0d2006e4SRobert Mustacchi 	}
384*0d2006e4SRobert Mustacchi 
385*0d2006e4SRobert Mustacchi 	for (i = 0; i < ud->usb_bos_nents; i++) {
386*0d2006e4SRobert Mustacchi 		usb_bos_t *bos = &ud->usb_bos[i];
387*0d2006e4SRobert Mustacchi 
388*0d2006e4SRobert Mustacchi 		switch (bos->ubos_type) {
389*0d2006e4SRobert Mustacchi 		case USB_BOS_TYPE_SUPERSPEED:
390*0d2006e4SRobert Mustacchi 			usba_add_superspeed_props(dip,
391*0d2006e4SRobert Mustacchi 			    &bos->ubos_caps.ubos_ssusb);
392*0d2006e4SRobert Mustacchi 			break;
393*0d2006e4SRobert Mustacchi 		case USB_BOS_TYPE_CONTAINER:
394*0d2006e4SRobert Mustacchi 			usba_add_container_props(dip,
395*0d2006e4SRobert Mustacchi 			    &bos->ubos_caps.ubos_container);
396*0d2006e4SRobert Mustacchi 			break;
397*0d2006e4SRobert Mustacchi 		default:
398*0d2006e4SRobert Mustacchi 			/*
399*0d2006e4SRobert Mustacchi 			 * This is a capability that we're not going to add
400*0d2006e4SRobert Mustacchi 			 * devinfo properties to describe.
401*0d2006e4SRobert Mustacchi 			 */
402*0d2006e4SRobert Mustacchi 			continue;
403*0d2006e4SRobert Mustacchi 		}
404*0d2006e4SRobert Mustacchi 	}
405*0d2006e4SRobert Mustacchi }
406*0d2006e4SRobert Mustacchi 
407*0d2006e4SRobert Mustacchi void
usba_free_binary_object_store(usba_device_t * ud)408*0d2006e4SRobert Mustacchi usba_free_binary_object_store(usba_device_t *ud)
409*0d2006e4SRobert Mustacchi {
410*0d2006e4SRobert Mustacchi 	if (ud->usb_bos_mp != NULL) {
411*0d2006e4SRobert Mustacchi 		freemsg(ud->usb_bos_mp);
412*0d2006e4SRobert Mustacchi 		ud->usb_bos_mp = NULL;
413*0d2006e4SRobert Mustacchi 	}
414*0d2006e4SRobert Mustacchi 
415*0d2006e4SRobert Mustacchi 	if (ud->usb_bos != NULL) {
416*0d2006e4SRobert Mustacchi 		kmem_free(ud->usb_bos, sizeof (usb_bos_t) * ud->usb_bos_nalloc);
417*0d2006e4SRobert Mustacchi 		ud->usb_bos = NULL;
418*0d2006e4SRobert Mustacchi 		ud->usb_bos_nalloc = ud->usb_bos_nents = 0;
419*0d2006e4SRobert Mustacchi 	}
420*0d2006e4SRobert Mustacchi }