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 }
421