xref: /illumos-gate/usr/src/uts/common/io/usb/usba/usbai_util.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2019 Joyent, Inc.
25  */
26 
27 
28 /*
29  * USBA: Solaris USB Architecture support
30  *
31  * Utility functions
32  */
33 #define	USBA_FRAMEWORK
34 #include <sys/usb/usba/usba_impl.h>
35 #include <sys/usb/usba/hcdi_impl.h>
36 #include <sys/strsun.h>
37 
38 extern void usba_free_evdata(usba_evdata_t *);
39 
40 static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
41 
42 /* local functions */
43 static	int	usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *,
44 			usba_pipe_async_req_t *, usb_flags_t);
45 static int	usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *,
46 			usba_pipe_async_req_t *, usb_flags_t);
47 static int	usba_sync_clear_feature(dev_info_t *, usba_ph_impl_t *,
48 			usba_pipe_async_req_t *, usb_flags_t);
49 
50 /*
51  * Wrapper functions returning parsed standard descriptors without
52  * getting the config cloud first but by just providing the dip.
53  *
54  * The client can easily retrieve the device and config descriptor from
55  * the usb registration and no separate functions are provided
56  *
57  * These functions return failure if the full descriptor can not be
58  * retrieved.  These functions will not access the device.
59  * The caller must allocate the buffer.
60  */
61 
62 /*
63  * usb_get_if_descr:
64  *	Function to get the cooked interface descriptor
65  *	This function will not access the device.
66  *
67  * Arguments:
68  *	dip			- pointer to devinfo of the client
69  *	if_index		- interface index
70  *	alt_setting	- alt interface setting
71  *	descr			- pointer to user allocated interface descr
72  *
73  * Return Values:
74  *	USB_SUCCESS	- descriptor is valid
75  *	USB_FAILURE	- full descriptor could not be retrieved
76  *	USB_*		- refer to usbai.h
77  */
78 int
79 usb_get_if_descr(dev_info_t	*dip,
80 		uint_t		if_index,
81 		uint_t		alt_setting,
82 		usb_if_descr_t	*descr)
83 {
84 	uchar_t		*usb_cfg;	/* buf for config descriptor */
85 	size_t		size, cfg_length;
86 
87 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
88 	    "usb_get_if_descr: %s, index=0x%x, alt#=0x%x",
89 	    ddi_node_name(dip), if_index, alt_setting);
90 
91 	if ((dip == NULL) || (descr == NULL)) {
92 
93 		return (USB_INVALID_ARGS);
94 	}
95 
96 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
97 	size = usb_parse_if_descr(usb_cfg, cfg_length,
98 	    if_index,	/* interface index */
99 	    alt_setting,	/* alt interface index */
100 	    descr,
101 	    USB_IF_DESCR_SIZE);
102 
103 	if (size != USB_IF_DESCR_SIZE) {
104 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
105 		    "parsing interface: size (%lu) != USB_IF_DESCR_SIZE (%d)",
106 		    size, USB_IF_DESCR_SIZE);
107 
108 		return (USB_FAILURE);
109 	}
110 
111 	return (USB_SUCCESS);
112 }
113 
114 
115 /*
116  * usb_get_ep_descr:
117  *	Function to get the cooked endpoint descriptor
118  *	This function will not access the device.
119  *
120  * Arguments:
121  *	dip			- pointer to devinfo of the client
122  *	if_index		- interface index
123  *	alt_setting		- alternate interface setting
124  *	endpoint_index		- endpoint index
125  *	descr			- pointer to user allocated interface descr
126  *
127  * Return Values:
128  *	USB_SUCCESS	- descriptor is valid
129  *	USB_FAILURE	- full descriptor could not be retrieved
130  *	USB_*		- refer to usbai.h
131  */
132 int
133 usb_get_ep_descr(dev_info_t	*dip,
134 		uint_t		if_index,
135 		uint_t		alt_setting,
136 		uint_t		endpoint_index,
137 		usb_ep_descr_t	*descr)
138 {
139 	uchar_t		*usb_cfg;	/* buf for config descriptor */
140 	size_t		size, cfg_length;
141 
142 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
143 	    "usb_get_ep_descr: %s, index=0x%x, alt#=0x%x",
144 	    ddi_node_name(dip), if_index, alt_setting);
145 
146 	if ((dip == NULL) || (descr == NULL)) {
147 
148 		return (USB_INVALID_ARGS);
149 	}
150 
151 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
152 	size = usb_parse_ep_descr(usb_cfg, cfg_length,
153 	    if_index,	/* interface index */
154 	    alt_setting,	/* alt interface index */
155 	    endpoint_index,		/* ep index */
156 	    descr, USB_EP_DESCR_SIZE);
157 
158 	if (size != USB_EP_DESCR_SIZE) {
159 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
160 		    "parsing endpoint: size (%lu) != USB_EP_DESCR_SIZE (%d)",
161 		    size, USB_EP_DESCR_SIZE);
162 
163 		return (USB_FAILURE);
164 	}
165 
166 	return (USB_SUCCESS);
167 }
168 
169 
170 /*
171  * usb_lookup_ep_data:
172  * usb_get_ep_data (deprecated):
173  *	Function to get specific endpoint descriptor data
174  *	This function will not access the device.
175  *
176  * Arguments:
177  *	dip		- pointer to dev info
178  *	usb_client_dev_data_t - pointer to registration data
179  *	interface	- requested interface
180  *	alternate	- requested alternate
181  *	skip		- how many to skip
182  *	type		- endpoint type
183  *	direction	- endpoint direction or USB_DIR_DONT_CARE
184  *
185  * Return Values:
186  *	NULL or an endpoint descriptor pointer
187  */
188 usb_ep_data_t *
189 usb_lookup_ep_data(dev_info_t	*dip,
190 		usb_client_dev_data_t *dev_datap,
191 		uint_t		interface,
192 		uint_t		alternate,
193 		uint_t		skip,
194 		uint_t		type,
195 		uint_t		dir)
196 {
197 	usb_alt_if_data_t	*altif_data;
198 	int			i;
199 
200 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
201 	    "usb_lookup_ep_data: "
202 	    "if=%d alt=%d skip=%d type=%d dir=%d",
203 	    interface, alternate, skip, type, dir);
204 
205 	if ((dip == NULL) || (dev_datap == NULL)) {
206 
207 		return (NULL);
208 	}
209 
210 	altif_data = &dev_datap->dev_curr_cfg->
211 	    cfg_if[interface].if_alt[alternate];
212 
213 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
214 	    "altif=0x%p n_ep=%d", (void *)altif_data, altif_data->altif_n_ep);
215 
216 	for (i = 0; i < altif_data->altif_n_ep; i++) {
217 		usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
218 		uint8_t	ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
219 		uint8_t ept_dir = ept->bEndpointAddress & USB_EP_DIR_MASK;
220 
221 		if (ept->bLength == 0) {
222 			continue;
223 		}
224 		if ((ept_type == type) &&
225 		    ((type == USB_EP_ATTR_CONTROL) || (dir == ept_dir))) {
226 
227 			if (skip-- == 0) {
228 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
229 				    usbai_log_handle,
230 				    "usb_get_ep_data: data=0x%p",
231 				    (void *)&altif_data->altif_ep[i]);
232 
233 				return (&altif_data->altif_ep[i]);
234 			}
235 		}
236 	}
237 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
238 	    "usb_get_ep_data: returning NULL");
239 
240 	return (NULL);
241 }
242 
243 
244 /*ARGSUSED*/
245 usb_ep_data_t *
246 usb_get_ep_data(dev_info_t	*dip,
247 		usb_client_dev_data_t *dev_datap,
248 		uint_t		interface,
249 		uint_t		alternate,
250 		uint_t		type,
251 		uint_t		dir)
252 {
253 	return (usb_lookup_ep_data(dip, dev_datap, interface,
254 	    alternate, 0, type, dir));
255 }
256 
257 
258 /*
259  * usb_get_string_descr:
260  *	Function to read the string descriptor
261  *	This function will access the device and block.
262  *
263  * Arguments:
264  *	dip		- pointer to devinfo of the client
265  *	langid		- LANGID to read different LOCALEs
266  *	index		- index to the string
267  *	buf		- user provided buffer for string descriptor
268  *	buflen		- user provided length of the buffer
269  *
270  * Return Values:
271  *	USB_SUCCESS	- descriptor is valid
272  *	USB_FAILURE	- full descriptor could not be retrieved
273  *	USB_*		- refer to usbai.h
274  */
275 int
276 usb_get_string_descr(dev_info_t *dip,
277 		uint16_t	langid,
278 		uint8_t 	index,
279 		char		*buf,
280 		size_t		buflen)
281 {
282 	mblk_t		*data = NULL;
283 	uint16_t	length;
284 	int		rval;
285 	usb_cr_t	completion_reason;
286 	size_t		len;
287 	usb_cb_flags_t	cb_flags;
288 
289 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
290 	    "usb_get_string_descr: %s, langid=0x%x index=0x%x",
291 	    ddi_node_name(dip), langid, index);
292 
293 	if ((dip == NULL) || (buf == NULL) || (buflen == 0) || (index == 0)) {
294 
295 		return (USB_INVALID_ARGS);
296 	}
297 
298 	/*
299 	 * determine the length of the descriptor
300 	 */
301 	rval = usb_pipe_sync_ctrl_xfer(dip,
302 	    usba_get_dflt_pipe_handle(dip),
303 	    USB_DEV_REQ_DEV_TO_HOST,
304 	    USB_REQ_GET_DESCR,
305 	    (USB_DESCR_TYPE_STRING << 8) | (index & 0xff),
306 	    langid,
307 	    4,
308 	    &data, USB_ATTRS_SHORT_XFER_OK,
309 	    &completion_reason,
310 	    &cb_flags, USB_FLAGS_SLEEP);
311 
312 	if (rval != USB_SUCCESS) {
313 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
314 		    "rval=%d cr=%d", rval, completion_reason);
315 
316 		goto done;
317 	}
318 	if (MBLKL(data) == 0) {
319 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
320 		    "0 bytes received");
321 
322 		goto done;
323 	}
324 
325 	ASSERT(data);
326 	length = *(data->b_rptr);
327 	freemsg(data);
328 	data = NULL;
329 
330 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
331 	    "rval=%d, cr=%d, length=%d", rval, completion_reason, length);
332 
333 	/*
334 	 * if length is zero the next control request may fail.
335 	 * the HCD may not support a zero length control request
336 	 * and return an mblk_t which is NULL along with rval
337 	 * being USB_SUCCESS and "cr" being USB_CR_OK
338 	 */
339 	if (length < 2) {
340 		rval = USB_FAILURE;
341 
342 		goto done;
343 	}
344 
345 	rval = usb_pipe_sync_ctrl_xfer(dip,
346 	    usba_get_dflt_pipe_handle(dip),
347 	    USB_DEV_REQ_DEV_TO_HOST,
348 	    USB_REQ_GET_DESCR,
349 	    (USB_DESCR_TYPE_STRING << 8) | (index & 0xff),
350 	    langid,
351 	    length,
352 	    &data, USB_ATTRS_SHORT_XFER_OK,
353 	    &completion_reason,
354 	    &cb_flags, USB_FLAGS_SLEEP);
355 
356 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
357 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
358 
359 	if ((data == NULL) || (rval != USB_SUCCESS)) {
360 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
361 		    "failed to get string descriptor (rval=%d cr=%d)",
362 		    rval, completion_reason);
363 
364 		goto done;
365 	}
366 
367 	if ((length = MBLKL(data)) != 0) {
368 		len = usba_ascii_string_descr(data->b_rptr, length, buf,
369 		    buflen);
370 		USB_DPRINTF_L4(DPRINT_MASK_USBA,
371 		    usbai_log_handle, "buf=%s buflen=%lu", buf, len);
372 
373 		ASSERT(len <= buflen);
374 	} else {
375 		rval = USB_FAILURE;
376 	}
377 done:
378 	freemsg(data);
379 
380 	return (rval);
381 }
382 
383 
384 /*
385  * usb_get_dev_descr:
386  *	 utility function to get device descriptor from usba_device
387  *
388  * Arguments:
389  *	dip		- pointer to devinfo of the client
390  *
391  * Return Values:
392  *	usb_dev_descr	- device  descriptor or NULL
393  */
394 usb_dev_descr_t *
395 usb_get_dev_descr(dev_info_t *dip)
396 {
397 	usba_device_t	*usba_device;
398 	usb_dev_descr_t *usb_dev_descr = NULL;
399 
400 	if (dip) {
401 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
402 		    "usb_get_dev_descr: %s", ddi_node_name(dip));
403 
404 		usba_device = usba_get_usba_device(dip);
405 		mutex_enter(&usba_device->usb_mutex);
406 		usb_dev_descr = usba_device->usb_dev_descr;
407 		mutex_exit(&usba_device->usb_mutex);
408 	}
409 
410 	return (usb_dev_descr);
411 }
412 
413 
414 /*
415  * usb_get_raw_cfg_data:
416  *	 utility function to get raw config descriptor from usba_device
417  *
418  * Arguments:
419  *	dip		- pointer to devinfo of the client
420  *	length		- pointer to copy the cfg length
421  *
422  * Return Values:
423  *	usb_cfg	- raw config descriptor
424  */
425 uchar_t *
426 usb_get_raw_cfg_data(dev_info_t *dip, size_t *length)
427 {
428 	usba_device_t	*usba_device;
429 	uchar_t		*usb_cfg;
430 
431 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
432 	    "usb_get_raw_cfg_data: %s", ddi_node_name(dip));
433 
434 	if ((dip == NULL) || (length == NULL)) {
435 
436 		return (NULL);
437 	}
438 
439 	usba_device = usba_get_usba_device(dip);
440 
441 	mutex_enter(&usba_device->usb_mutex);
442 	usb_cfg = usba_device->usb_cfg;
443 	*length = usba_device->usb_cfg_length;
444 	mutex_exit(&usba_device->usb_mutex);
445 
446 	return (usb_cfg);
447 }
448 
449 
450 /*
451  * usb_get_addr:
452  *	utility function to return current usb address, mostly
453  *	for debugging purposes
454  *
455  * Arguments:
456  *	dip	- pointer to devinfo of the client
457  *
458  * Return Values:
459  *	address	- USB Device Address
460  */
461 int
462 usb_get_addr(dev_info_t *dip)
463 {
464 	int address = 0;
465 
466 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
467 	    "usb_get_addr: %s", ddi_node_name(dip));
468 
469 	if (dip) {
470 		usba_device_t	*usba_device = usba_get_usba_device(dip);
471 
472 		mutex_enter(&usba_device->usb_mutex);
473 		address = usba_device->usb_addr;
474 		mutex_exit(&usba_device->usb_mutex);
475 	}
476 
477 	return (address);
478 }
479 
480 
481 /*
482  * usb_set_cfg():
483  *	set configuration, use with caution (issues USB_REQ_SET_CONFIG)
484  *	Changing configuration will fail if pipes are still open or when
485  *	invoked from a driver bound to an interface on a composite device.
486  *
487  *	This function will access the device and block
488  *
489  * Arguments:
490  *	dip		- pointer to devinfo of the client
491  *	cfg_index	- config index
492  *	cfg_value	- config value to be set
493  *	flags		- USB_FLAGS_SLEEP:
494  *				wait for completion
495  *	cb		- if USB_FLAGS_SLEEP has not been specified
496  *			  this callback function will be called on
497  *			  completion. This callback may be NULL
498  *			  and no notification of completion will then
499  *			  be provided.
500  *	cb_arg		- 2nd argument to callback function.
501  *
502  * Return Values:
503  *	USB_SUCCESS:	- new configuration was set
504  *	USB_FAILURE:	- new configuration could not be set
505  *	USB_BUSY:	- some pipes were open or there were children
506  *	USB_*		- refer to usbai.h
507  */
508 int
509 usb_set_cfg(dev_info_t		*dip,
510 		uint_t		cfg_index,
511 		usb_flags_t	usb_flags,
512 		void		(*cb)(
513 					usb_pipe_handle_t ph,
514 					usb_opaque_t	arg,
515 					int		rval,
516 					usb_cb_flags_t	flags),
517 		usb_opaque_t	cb_arg)
518 {
519 	usb_pipe_handle_t	ph;
520 
521 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
522 	    "usb_set_cfg: %s%d, cfg_index = 0x%x, uf = 0x%x",
523 	    ddi_driver_name(dip), ddi_get_instance(dip), cfg_index,
524 	    usb_flags);
525 
526 	if (dip == NULL) {
527 
528 		return (USB_INVALID_ARGS);
529 	}
530 
531 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
532 
533 		return (USB_INVALID_CONTEXT);
534 	}
535 
536 	if (!usb_owns_device(dip)) {
537 
538 		return (USB_INVALID_PERM);
539 	}
540 
541 	ph = usba_get_dflt_pipe_handle(dip);
542 	if (usba_hold_ph_data(ph) == NULL) {
543 
544 		return (USB_INVALID_PIPE);
545 	}
546 
547 	return (usba_pipe_setup_func_call(dip,
548 	    usba_sync_set_cfg, (usba_ph_impl_t *)ph,
549 	    (usb_opaque_t)((uintptr_t)cfg_index), usb_flags, cb, cb_arg));
550 }
551 
552 
553 static int
554 usba_sync_set_cfg(dev_info_t	*dip,
555 		usba_ph_impl_t	*ph_impl,
556 		usba_pipe_async_req_t	*request,
557 		usb_flags_t	flags)
558 {
559 	int		rval;
560 	usb_cr_t	completion_reason;
561 	usb_cb_flags_t	cb_flags;
562 	usba_device_t	*usba_device;
563 	int		i, ph_open_cnt;
564 	uint_t		cfg_index = (uint_t)((uintptr_t)(request->arg));
565 	size_t		size;
566 	usb_cfg_descr_t confdescr;
567 	dev_info_t	*pdip;
568 
569 	usba_device = usba_get_usba_device(dip);
570 
571 	/*
572 	 * default pipe is still open
573 	 * all other pipes should be closed
574 	 */
575 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
576 		if (usba_device->usb_ph_list[i].usba_ph_data) {
577 			ph_open_cnt++;
578 			break;
579 		}
580 	}
581 
582 	if (ph_open_cnt || ddi_get_child(dip)) {
583 		usba_release_ph_data(ph_impl);
584 
585 		return (USB_BUSY);
586 	}
587 
588 	/*
589 	 * check if the configuration meets the
590 	 * power budget requirement
591 	 */
592 	if (usba_is_root_hub(dip)) {
593 		/*
594 		 * root hub should never be multi-configured.
595 		 * the code is here just to ensure
596 		 */
597 		usba_release_ph_data(ph_impl);
598 
599 		return (USB_FAILURE);
600 	}
601 	pdip = ddi_get_parent(dip);
602 
603 	/*
604 	 * increase the power budget value back to the unconfigured
605 	 * state to eliminate the influence of the old configuration
606 	 * before checking the new configuration; but remember to
607 	 * make a decrement before leaving this routine to restore
608 	 * the power consumption state of the device no matter it
609 	 * is in the new or old configuration
610 	 */
611 	usba_hubdi_incr_power_budget(pdip, usba_device);
612 
613 	if ((usba_hubdi_check_power_budget(pdip, usba_device,
614 	    cfg_index)) != USB_SUCCESS) {
615 		usba_hubdi_decr_power_budget(pdip, usba_device);
616 
617 		usba_release_ph_data(ph_impl);
618 
619 		return (USB_FAILURE);
620 	}
621 
622 	size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index],
623 	    USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE);
624 
625 	/* hubdi should ensure that this descriptor is correct */
626 	ASSERT(size == USB_CFG_DESCR_SIZE);
627 
628 	/* set the configuration */
629 	rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl,
630 	    USB_DEV_REQ_HOST_TO_DEV,
631 	    USB_REQ_SET_CFG,
632 	    confdescr.bConfigurationValue,
633 	    0,
634 	    0,
635 	    NULL, 0,
636 	    &completion_reason,
637 	    &cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP);
638 
639 	if (rval == USB_SUCCESS) {
640 		mutex_enter(&usba_device->usb_mutex);
641 		usba_device->usb_cfg_value = confdescr.bConfigurationValue;
642 		usba_device->usb_active_cfg_ndx = cfg_index;
643 		usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index];
644 		usba_device->usb_cfg_length = confdescr.wTotalLength;
645 		mutex_exit(&usba_device->usb_mutex);
646 
647 		/* update the configuration property */
648 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
649 		    "configuration#", usba_device->usb_cfg_value);
650 	}
651 
652 	/*
653 	 * usba_device->usb_cfg always stores current configuration
654 	 * descriptor no matter SET_CFG request succeeded or not,
655 	 * so usba_hubdi_decr_power_budget can be done regardless
656 	 * of rval above
657 	 */
658 	usba_hubdi_decr_power_budget(pdip, usba_device);
659 
660 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
661 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
662 
663 	usba_release_ph_data(ph_impl);
664 
665 	return (rval);
666 }
667 
668 
669 
670 /*
671  * usb_get_cfg():
672  *	get configuration value
673  *
674  * Arguments:
675  *	dip		- pointer to devinfo of the client
676  *	cfg_value	- current config value
677  *	flags		- none, always blocks
678  *
679  * Return Values:
680  *	USB_SUCCESS:	- config value was retrieved
681  *	USB_FAILURE:	- config value could not be retrieved
682  *	USB_*		- refer to usbai.h
683  */
684 int
685 usb_get_cfg(dev_info_t		*dip,
686 		uint_t		*cfgval,
687 		usb_flags_t	flags)
688 {
689 	int		rval;
690 	usb_cr_t	completion_reason;
691 	mblk_t		*data = NULL;
692 	usb_cb_flags_t	cb_flags;
693 	usb_pipe_handle_t ph;
694 
695 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
696 	    "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags);
697 
698 	if ((cfgval == NULL) || (dip == NULL)) {
699 
700 		return (USB_INVALID_ARGS);
701 	}
702 
703 	ph = usba_get_dflt_pipe_handle(dip);
704 
705 	/*
706 	 * get the cfg value
707 	 */
708 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
709 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV,
710 	    USB_REQ_GET_CFG,
711 	    0,
712 	    0,
713 	    1,		/* returns one byte of data */
714 	    &data, 0,
715 	    &completion_reason,
716 	    &cb_flags, flags);
717 
718 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
719 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
720 
721 	if ((rval == USB_SUCCESS) && data &&
722 	    (MBLKL(data) == 1)) {
723 		*cfgval = *(data->b_rptr);
724 	} else {
725 		*cfgval = 1;
726 		if (rval == USB_SUCCESS) {
727 			rval = USB_FAILURE;
728 		}
729 	}
730 
731 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
732 	    "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval);
733 
734 	freemsg(data);
735 
736 	return (rval);
737 }
738 
739 
740 /*
741  * usb_get_current_cfgidx:
742  *	get current current config index
743  */
744 uint_t
745 usb_get_current_cfgidx(dev_info_t *dip)
746 {
747 	usba_device_t	*usba_device = usba_get_usba_device(dip);
748 	uint_t		ndx;
749 
750 	mutex_enter(&usba_device->usb_mutex);
751 	ndx = usba_device->usb_active_cfg_ndx;
752 	mutex_exit(&usba_device->usb_mutex);
753 
754 	return (ndx);
755 }
756 
757 
758 /*
759  * usb_get_if_number:
760  *	get usb interface number of current OS device node.
761  *
762  * Arguments:
763  *	dip		- pointer to devinfo of the client
764  *
765  * Return Values:
766  *	USB_COMBINED_NODE if the driver is responsible for the entire
767  *	    device and this dip doesn't correspond to a device node.
768  *	USB_DEVICE_NODE if the driver is responsible for the entire device
769  *	    and this dip corresponds to a device node.
770  *	interface number: otherwise.
771  */
772 int
773 usb_get_if_number(dev_info_t *dip)
774 {
775 	int interface_num;
776 	usba_device_t	*usba_device = usba_get_usba_device(dip);
777 	usb_dev_descr_t	*usb_dev_descr;
778 
779 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
780 	    "usb_get_if_number: dip = 0x%p", (void *)dip);
781 
782 	/* not quite right but we can't return a negative return value */
783 	if (dip == NULL) {
784 
785 		return (0);
786 	}
787 
788 	if (usba_device) {
789 		usb_dev_descr = usba_device->usb_dev_descr;
790 	} else {
791 
792 		return (0);
793 	}
794 
795 	interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
796 	    DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE);
797 
798 	if (interface_num == USB_COMBINED_NODE) {
799 		if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
800 		    (usb_dev_descr->bDeviceClass == 0)) &&
801 		    (usba_device->usb_n_cfgs == 1) &&
802 		    (usba_device->usb_n_ifs == 1))) {
803 			interface_num = USB_DEVICE_NODE;
804 		}
805 	}
806 
807 	return (interface_num);
808 }
809 
810 
811 boolean_t
812 usb_owns_device(dev_info_t *dip)
813 {
814 	int interface_num = usb_get_if_number(dip);
815 
816 	return (interface_num < 0 ? B_TRUE : B_FALSE);
817 }
818 
819 
820 /* check whether the interface is in this interface association */
821 boolean_t
822 usba_check_if_in_ia(dev_info_t *dip, int n_if)
823 {
824 	int first_if, if_count;
825 
826 	first_if = usb_get_if_number(dip);
827 	if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
828 	    DDI_PROP_DONTPASS, "interface-count", -1);
829 	if_count += first_if;
830 
831 	return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE);
832 }
833 
834 
835 uint8_t
836 usba_get_ifno(dev_info_t *dip)
837 {
838 	int interface_num = usb_get_if_number(dip);
839 
840 	return (uint8_t)(interface_num < 0 ? 0 : interface_num);
841 }
842 
843 
844 /*
845  * usb_set_alt_if:
846  *	set the alternate interface number. Issues USB_REQ_SET_IF
847  *	This function will access the device
848  *
849  * Arguments:
850  *	dip		- pointer to devinfo of the client
851  *	if_number	- interface number
852  *	alt_number	- alternate interface number
853  *	flags		- USB_FLAGS_SLEEP:
854  *				wait for completion
855  *	cb		- if USB_FLAGS_SLEEP has not been specified
856  *			  this callback function will be called on
857  *			  completion. This callback may be NULL
858  *			  and no notification of completion will then
859  *			  be provided.
860  *	cb_arg		- 2nd argument to callback function.
861  *
862  *
863  * return values:
864  *	USB_SUCCESS	- alternate was set
865  *	USB_FAILURE	- alternate could not be set because pipes
866  *			  were still open or some access error occurred
867  *	USB_*		- refer to usbai.h
868  *
869  * Note:
870  *	we can't easily check if all pipes to endpoints for this interface
871  *	are closed since we don't have a map of which endpoints belong
872  *	to which interface. If we had this map, we would need to update
873  *	this on each alternative or configuration switch
874  */
875 int
876 usb_set_alt_if(dev_info_t	*dip,
877 		uint_t		interface,
878 		uint_t		alt_number,
879 		usb_flags_t	usb_flags,
880 		void		(*cb)(
881 					usb_pipe_handle_t ph,
882 					usb_opaque_t	arg,
883 					int		rval,
884 					usb_cb_flags_t	flags),
885 		usb_opaque_t	cb_arg)
886 {
887 	usb_pipe_handle_t	ph;
888 
889 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
890 	    "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
891 	    ddi_driver_name(dip), ddi_get_instance(dip),
892 	    interface, alt_number, usb_flags);
893 
894 	if (dip == NULL) {
895 
896 		return (USB_INVALID_ARGS);
897 	}
898 
899 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
900 
901 		return (USB_INVALID_CONTEXT);
902 	}
903 
904 	ph = usba_get_dflt_pipe_handle(dip);
905 	if (usba_hold_ph_data(ph) == NULL) {
906 
907 		return (USB_INVALID_PIPE);
908 	}
909 
910 	return (usba_pipe_setup_func_call(dip,
911 	    usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
912 	    (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
913 	    usb_flags, cb, cb_arg));
914 }
915 
916 
917 static int
918 usba_sync_set_alt_if(dev_info_t	*dip,
919 		usba_ph_impl_t	*ph_impl,
920 		usba_pipe_async_req_t	*request,
921 		usb_flags_t	flags)
922 {
923 	int		rval;
924 	usb_cr_t	completion_reason;
925 	usb_cb_flags_t	cb_flags;
926 	usb_opaque_t	arg = request->arg;
927 	int		interface = ((uintptr_t)arg >> 8) & 0xff;
928 	int		alt_number = (uintptr_t)arg & 0xff;
929 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
930 	    (usb_pipe_handle_t)ph_impl);
931 
932 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
933 	    "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
934 	    "uf=0x%x", ddi_node_name(dip), interface,
935 	    alt_number, flags);
936 
937 	/* if we don't own the device, we must own the interface or ia */
938 	if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) &&
939 	    (interface != usb_get_if_number(dip))) {
940 		usba_release_ph_data(ph_data->p_ph_impl);
941 
942 		return (USB_INVALID_PERM);
943 	}
944 
945 	/* set the alternate setting */
946 	rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
947 	    USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
948 	    USB_REQ_SET_IF,
949 	    alt_number,
950 	    interface,
951 	    0,
952 	    NULL, 0,
953 	    &completion_reason,
954 	    &cb_flags, flags | USB_FLAGS_SLEEP);
955 
956 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
957 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
958 
959 	usba_release_ph_data(ph_data->p_ph_impl);
960 
961 	return (rval);
962 }
963 
964 
965 /*
966  * usb_get_alt_if:
967  *	get the alternate interface number. Issues USB_REQ_GET_IF
968  *	This function will access the device and block
969  *
970  * Arguments:
971  *	dip			- pointer to devinfo of the client
972  *	if_number	- interface number
973  *	alt_number	- alternate interface number
974  *	flags			- none but USB_FLAGS_SLEEP may be passed
975  *
976  * return values:
977  *	USB_SUCCESS:		alternate was set
978  *	USB_FAILURE:		alternate could not be set because pipes
979  *				were still open or some access error occurred
980  */
981 int
982 usb_get_alt_if(dev_info_t	*dip,
983 		uint_t		if_number,
984 		uint_t		*alt_number,
985 		usb_flags_t	flags)
986 {
987 	int		rval;
988 	usb_cr_t	completion_reason;
989 	mblk_t		*data = NULL;
990 	usb_cb_flags_t	cb_flags;
991 	usb_pipe_handle_t ph;
992 
993 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
994 	    "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
995 	    "uf = 0x%x", ddi_node_name(dip), if_number,
996 	    (void *)alt_number, flags);
997 
998 	if ((alt_number == NULL) || (dip == NULL)) {
999 
1000 		return (USB_INVALID_ARGS);
1001 	}
1002 
1003 	ph = usba_get_dflt_pipe_handle(dip);
1004 
1005 	/*
1006 	 * get the alternate setting
1007 	 */
1008 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1009 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
1010 	    USB_REQ_GET_IF,
1011 	    0,
1012 	    if_number,
1013 	    1,		/* returns one byte of data */
1014 	    &data, 0,
1015 	    &completion_reason,
1016 	    &cb_flags, flags);
1017 
1018 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1019 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
1020 
1021 	if ((rval == USB_SUCCESS) && data &&
1022 	    (MBLKL(data) == 1)) {
1023 		*alt_number = *(data->b_rptr);
1024 	} else {
1025 		*alt_number = 0;
1026 		if (rval == USB_SUCCESS) {
1027 			rval = USB_FAILURE;
1028 		}
1029 	}
1030 
1031 	freemsg(data);
1032 
1033 	return (rval);
1034 }
1035 
1036 
1037 /*
1038  * usba_get_cfg_cloud:
1039  *	Get descriptor cloud for a given configuration.
1040  *
1041  * Arguments:
1042  *	dip			- pointer to devinfo of the client
1043  *	default_ph		- default pipe handle
1044  *	cfg			- which configuration to retrieve raw cloud of
1045  *
1046  * Returns:
1047  *	on success: mblock containing the raw data.  Caller must free.
1048  *	on failure: NULL
1049  */
1050 static mblk_t *
1051 usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
1052 {
1053 	usb_cr_t	completion_reason;
1054 	usb_cb_flags_t	cb_flags;
1055 	usb_cfg_descr_t cfg_descr;
1056 	mblk_t		*pdata = NULL;
1057 
1058 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1059 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1060 	    USB_REQ_GET_DESCR,
1061 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1062 	    0,
1063 	    USB_CFG_DESCR_SIZE,
1064 	    &pdata,
1065 	    0,
1066 	    &completion_reason,
1067 	    &cb_flags,
1068 	    0) != USB_SUCCESS) {
1069 
1070 		freemsg(pdata);
1071 
1072 		return (NULL);
1073 	}
1074 
1075 	(void) usb_parse_cfg_descr(pdata->b_rptr,
1076 	    MBLKL(pdata), &cfg_descr, USB_CFG_DESCR_SIZE);
1077 	freemsg(pdata);
1078 	pdata = NULL;
1079 
1080 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1081 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1082 	    USB_REQ_GET_DESCR,
1083 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1084 	    0,
1085 	    cfg_descr.wTotalLength,
1086 	    &pdata,
1087 	    0,
1088 	    &completion_reason,
1089 	    &cb_flags,
1090 	    0) != USB_SUCCESS) {
1091 
1092 		freemsg(pdata);
1093 
1094 		return (NULL);
1095 	}
1096 
1097 	return (pdata);
1098 }
1099 
1100 /*
1101  * usb_check_same_device:
1102  *	Check if the device connected to the port is the same as
1103  *	the previous device that was in the port.  The previous device is
1104  *	represented by the dip on record for the port.	Print a message
1105  *	if the device is different.  If device_string arg is not NULL, it is
1106  *	included in the message.  Can block.
1107  *
1108  * Arguments:
1109  *	dip			- pointer to devinfo of the client
1110  *	log_handle		- handle to which messages are logged
1111  *	log_level		- one of USB_LOG_*
1112  *	log_mask		- logging mask
1113  *	check_mask		- one mask containing things to check:
1114  *					USB_CHK_BASIC: empty mask;
1115  *						these checks are always done.
1116  *					USB_CHK_VIDPID:
1117  *						check vid, pid only.
1118  *					USB_CHK_SERIAL: check match on device
1119  *						serial number.
1120  *					USB_CHK_CFG: check all raw config
1121  *						clouds for a match.
1122  *				NOTE: descr length and content always checked
1123  *	device_string		- Device string to appear in error message
1124  *
1125  * return values:
1126  *	USB_SUCCESS:		same device
1127  *	USB_INVALID_VERSION	not same device
1128  *	USB_FAILURE:		Failure processing request
1129  *	USB_INVALID_ARG:	dip is invalid
1130  */
1131 int
1132 usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
1133     int log_level, int log_mask, uint_t check_mask, char *device_string)
1134 {
1135 	usb_dev_descr_t		usb_dev_descr;
1136 	usba_device_t		*usba_device;
1137 	mblk_t			*pdata = NULL;
1138 	uint16_t		length;
1139 	int			rval;
1140 	char			*buf;
1141 	usb_cr_t		completion_reason;
1142 	usb_cb_flags_t		cb_flags;
1143 	boolean_t		match = B_TRUE;
1144 	usb_pipe_handle_t	def_ph;
1145 
1146 	if (dip == NULL) {
1147 
1148 		return (USB_INVALID_ARGS);
1149 	}
1150 
1151 	usba_device = usba_get_usba_device(dip);
1152 	length = usba_device->usb_dev_descr->bLength;
1153 	def_ph = usba_get_dflt_pipe_handle(dip);
1154 	ASSERT(def_ph);
1155 
1156 	/* get the "new" device descriptor */
1157 	rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
1158 	    USB_DEV_REQ_DEV_TO_HOST |
1159 	    USB_DEV_REQ_TYPE_STANDARD,
1160 	    USB_REQ_GET_DESCR,		/* bRequest */
1161 	    USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
1162 	    0,				/* wIndex */
1163 	    length,				/* wLength */
1164 	    &pdata, 0,
1165 	    &completion_reason,
1166 	    &cb_flags, USB_FLAGS_SLEEP);
1167 
1168 	if (rval != USB_SUCCESS) {
1169 		if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
1170 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
1171 			    "getting device descriptor failed (%d)", rval);
1172 			freemsg(pdata);
1173 
1174 			return (USB_FAILURE);
1175 		}
1176 	}
1177 
1178 	ASSERT(pdata != NULL);
1179 
1180 	(void) usb_parse_dev_descr(pdata->b_rptr,
1181 	    MBLKL(pdata), &usb_dev_descr,
1182 	    sizeof (usb_dev_descr_t));
1183 
1184 	freemsg(pdata);
1185 	pdata = NULL;
1186 
1187 	/* Always check the device descriptor length. */
1188 	if (usb_dev_descr.bLength != length) {
1189 		match = B_FALSE;
1190 	}
1191 
1192 	if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
1193 		match = (usba_device->usb_dev_descr->idVendor ==
1194 		    usb_dev_descr.idVendor) &&
1195 		    (usba_device->usb_dev_descr->idProduct ==
1196 		    usb_dev_descr.idProduct);
1197 	} else if (bcmp((char *)usba_device->usb_dev_descr,
1198 	    (char *)&usb_dev_descr, length) != 0) {
1199 		match = B_FALSE;
1200 	}
1201 
1202 	/* if requested & this device has a serial number check and compare */
1203 	if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
1204 	    (usba_device->usb_serialno_str != NULL)) {
1205 		buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1206 		if (usb_get_string_descr(dip, USB_LANG_ID,
1207 		    usb_dev_descr.iSerialNumber, buf,
1208 		    USB_MAXSTRINGLEN) == USB_SUCCESS) {
1209 			match =
1210 			    (strcmp(buf, usba_device->usb_serialno_str) == 0);
1211 		}
1212 		kmem_free(buf, USB_MAXSTRINGLEN);
1213 	}
1214 
1215 	if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) {
1216 
1217 		uint8_t num_cfgs = usb_dev_descr.bNumConfigurations;
1218 		uint8_t cfg;
1219 		mblk_t *cloud;
1220 
1221 		for (cfg = 0; cfg < num_cfgs; cfg++) {
1222 			cloud = usba_get_cfg_cloud(dip, def_ph, cfg);
1223 			if (cloud == NULL) {
1224 				USB_DPRINTF_L3(DPRINT_MASK_USBA,
1225 				    usbai_log_handle,
1226 				    "Could not retrieve config cloud for "
1227 				    "comparison");
1228 				break;
1229 			}
1230 
1231 			if (bcmp((char *)cloud->b_rptr,
1232 			    usba_device->usb_cfg_array[cfg],
1233 			    MBLKL(cloud)) != 0) {
1234 				freemsg(cloud);
1235 				break;
1236 			}
1237 
1238 			freemsg(cloud);
1239 		}
1240 		if (cfg != num_cfgs) {
1241 			match = B_FALSE;
1242 		}
1243 	}
1244 
1245 	if (match == B_FALSE) {
1246 		boolean_t allocated_here = (device_string == NULL);
1247 		if (allocated_here) {
1248 			device_string =
1249 			    kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP);
1250 			(void) usba_get_mfg_prod_sn_str(dip, device_string,
1251 			    USB_MAXSTRINGLEN);
1252 		}
1253 		if (device_string[0] != '\0') {
1254 			(void) usb_log(log_handle, log_level, log_mask,
1255 			    "Cannot access %s.	Please reconnect.",
1256 			    device_string);
1257 		} else {
1258 			(void) usb_log(log_handle, log_level, log_mask,
1259 			    "Device is not identical to the "
1260 			    "previous one this port.\n"
1261 			    "Please disconnect and reconnect");
1262 		}
1263 		if (allocated_here) {
1264 			kmem_free(device_string, USB_MAXSTRINGLEN);
1265 		}
1266 
1267 		return (USB_INVALID_VERSION);
1268 	}
1269 
1270 	return (USB_SUCCESS);
1271 }
1272 
1273 
1274 /*
1275  * usb_pipe_get_state:
1276  *	Return the state of the pipe
1277  *
1278  * Arguments:
1279  *	pipe_handle	- pipe_handle pointer
1280  *	pipe_state	- pointer to copy pipe state to
1281  *	flags:
1282  *		not used other than to check context
1283  *
1284  * Return Values:
1285  *	USB_SUCCESS	- port state returned
1286  *	USB_*		- refer to usbai.h
1287  */
1288 int
1289 usb_pipe_get_state(usb_pipe_handle_t	pipe_handle,
1290 	    usb_pipe_state_t	*pipe_state,
1291 	    usb_flags_t		usb_flags)
1292 {
1293 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1294 
1295 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1296 	    "usb_pipe_get_state: ph_data=0x%p uf=0x%x", (void *)ph_data,
1297 	    usb_flags);
1298 
1299 	if (pipe_state == NULL) {
1300 		if (ph_data) {
1301 			usba_release_ph_data(ph_data->p_ph_impl);
1302 		}
1303 
1304 		return (USB_INVALID_ARGS);
1305 	}
1306 
1307 	if (ph_data == NULL) {
1308 		*pipe_state = USB_PIPE_STATE_CLOSED;
1309 
1310 		return (USB_SUCCESS);
1311 	}
1312 
1313 	mutex_enter(&ph_data->p_mutex);
1314 	*pipe_state = usba_get_ph_state(ph_data);
1315 	mutex_exit(&ph_data->p_mutex);
1316 
1317 	usba_release_ph_data(ph_data->p_ph_impl);
1318 
1319 	return (USB_SUCCESS);
1320 }
1321 
1322 
1323 /*
1324  * usba_pipe_get_policy:
1325  *	Return a pipe's policy
1326  *
1327  * Arguments:
1328  *	pipe_handle	- pipe_handle pointer
1329  *
1330  * Return Values:
1331  *	On success: the pipe's policy
1332  *	On failure: NULL
1333  */
1334 usb_pipe_policy_t
1335 *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)
1336 {
1337 	usb_pipe_policy_t *pp = NULL;
1338 
1339 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1340 
1341 	if (ph_data) {
1342 		pp = &ph_data->p_policy;
1343 
1344 		usba_release_ph_data(ph_data->p_ph_impl);
1345 	}
1346 
1347 	return (pp);
1348 }
1349 
1350 
1351 /*
1352  * usb_ep_num:
1353  *	Return the endpoint number for a given pipe handle
1354  *
1355  * Arguments:
1356  *	pipe_handle	- pipe_handle pointer
1357  *
1358  * Return Values:
1359  *	endpoint number
1360  */
1361 int
1362 usb_ep_num(usb_pipe_handle_t pipe_handle)
1363 {
1364 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1365 	int ep_num;
1366 
1367 	if (ph_data == NULL) {
1368 
1369 		return (USB_INVALID_PIPE);
1370 	}
1371 
1372 	mutex_enter(&ph_data->p_mutex);
1373 	ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
1374 	mutex_exit(&ph_data->p_mutex);
1375 
1376 	usba_release_ph_data(ph_data->p_ph_impl);
1377 
1378 	return (ep_num);
1379 }
1380 
1381 
1382 /*
1383  * usb_get_status
1384  *	Issues USB_REQ_GET_STATUS to device/endpoint/interface
1385  *	and report in "status" arg.
1386  *
1387  *	status reported for a "device" is
1388  *		RemoteWakeup enabled
1389  *		SelfPowered device?
1390  *
1391  *	status reported for an "interface" is NONE.
1392  *	status reported for an "endpoint" is
1393  *		HALT set (device STALLED?)
1394  *
1395  * Arguments:
1396  *	dip	- pointer to devinfo of the client
1397  *	ph	- pipe handle
1398  *	type	- bmRequestType to be used
1399  *	what	- 0 for device, otherwise interface or ep number
1400  *	status	- user supplied pointer for storing the status
1401  *	flags	- USB_FLAGS_SLEEP (mandatory)
1402  *
1403  * Return Values:
1404  *	valid usb_status_t	or USB_FAILURE
1405  */
1406 int
1407 usb_get_status(dev_info_t		*dip,
1408 		usb_pipe_handle_t	ph,
1409 		uint_t			type,	/* bmRequestType */
1410 		uint_t			what,	/* 0, interface, ept number */
1411 		uint16_t		*status,
1412 		usb_flags_t		flags)
1413 {
1414 	int		rval;
1415 	usb_cr_t	completion_reason;
1416 	mblk_t		*data = NULL;
1417 	usb_cb_flags_t	cb_flags;
1418 
1419 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1420 	    "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
1421 	    type, what, flags);
1422 
1423 	if ((status == NULL) || (dip == NULL)) {
1424 
1425 		return (USB_INVALID_ARGS);
1426 	}
1427 	if (ph == NULL) {
1428 
1429 		return (USB_INVALID_PIPE);
1430 	}
1431 
1432 	type |= USB_DEV_REQ_DEV_TO_HOST;
1433 
1434 	/* get the status */
1435 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1436 	    type,
1437 	    USB_REQ_GET_STATUS,
1438 	    0,
1439 	    what,
1440 	    USB_GET_STATUS_LEN,	/* status is fixed 2 bytes long */
1441 	    &data, 0,
1442 	    &completion_reason, &cb_flags, flags);
1443 
1444 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1445 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1446 
1447 	if ((rval == USB_SUCCESS) && data &&
1448 	    (MBLKL(data) == USB_GET_STATUS_LEN)) {
1449 		*status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
1450 	} else {
1451 		*status = 0;
1452 		if (rval == USB_SUCCESS) {
1453 			rval = USB_FAILURE;
1454 		}
1455 	}
1456 
1457 	freemsg(data);
1458 
1459 	return (rval);
1460 }
1461 
1462 
1463 /*
1464  * usb_clear_feature:
1465  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1466  *
1467  * Arguments:
1468  *	dip		- pointer to devinfo of the client
1469  *	ph		- pipe handle pointer
1470  *	type		- bmRequestType to be used
1471  *	feature		- feature to be cleared
1472  *	what		- 0 for device, otherwise interface or ep number
1473  *	flags		- none (but will sleep)
1474  *
1475  * Return Values:
1476  *	USB_SUCCESS	- on doing a successful clear feature
1477  *	USB_FAILURE	- on failure
1478  *	USB_*		- refer to usbai.h
1479  */
1480 int
1481 usb_clear_feature(dev_info_t		*dip,
1482 		usb_pipe_handle_t	ph,
1483 		uint_t			type,	/* bmRequestType */
1484 		uint_t			feature,
1485 		uint_t			what,	/* 0, interface, ept number */
1486 		usb_flags_t		flags)
1487 {
1488 	int		rval;
1489 	usb_cr_t	completion_reason;
1490 	usb_cb_flags_t	cb_flags;
1491 
1492 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1493 	    "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1494 	    "uf = 0x%x", type, feature, what, flags);
1495 
1496 	if (dip == NULL) {
1497 
1498 		return (USB_INVALID_ARGS);
1499 	}
1500 	if (ph == NULL) {
1501 
1502 		return (USB_INVALID_PIPE);
1503 	}
1504 
1505 	/* issue Clear feature */
1506 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1507 	    type,
1508 	    USB_REQ_CLEAR_FEATURE,
1509 	    feature,
1510 	    what,
1511 	    0,
1512 	    NULL, 0,
1513 	    &completion_reason,
1514 	    &cb_flags, flags | USB_FLAGS_SLEEP);
1515 
1516 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1517 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1518 
1519 	return (rval);
1520 }
1521 
1522 
1523 /*
1524  * usb_clr_feature:
1525  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1526  *
1527  * Arguments:
1528  *	dip		- pointer to devinfo of the client
1529  *	type		- bmRequestType to be used
1530  *	feature		- feature to be cleared
1531  *	what		- 0 for device, otherwise interface or ep number
1532  *	flags		- USB_FLAGS_SLEEP:
1533  *				wait for completion
1534  *	cb		- if USB_FLAGS_SLEEP has not been specified
1535  *			  this callback function will be called on
1536  *			  completion. This callback may be NULL
1537  *			  and no notification of completion will then
1538  *			  be provided.
1539  *	cb_arg		- 2nd argument to callback function.
1540  *
1541  *
1542  * Return Values:
1543  *	USB_SUCCESS	- on doing a successful clear feature
1544  *	USB_FAILURE	- on failure
1545  *	USB_*		- refer to usbai.h
1546  */
1547 int
1548 usb_clr_feature(
1549 		dev_info_t	*dip,
1550 		uint_t		type,	/* bmRequestType */
1551 		uint_t		feature,
1552 		uint_t		what,	/* 0, interface, ept number */
1553 		usb_flags_t	flags,
1554 		void		(*cb)(
1555 					usb_pipe_handle_t ph,
1556 					usb_opaque_t	arg,
1557 					int		rval,
1558 					usb_cb_flags_t	flags),
1559 		usb_opaque_t	cb_arg)
1560 {
1561 	usb_pipe_handle_t ph;
1562 
1563 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1564 	    "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1565 	    "uf = 0x%x", type, feature, what, flags);
1566 
1567 	if (dip == NULL) {
1568 
1569 		return (USB_INVALID_ARGS);
1570 	}
1571 
1572 	if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1573 
1574 		return (USB_INVALID_CONTEXT);
1575 	}
1576 
1577 	ph = usba_get_dflt_pipe_handle(dip);
1578 	if (usba_hold_ph_data(ph) == NULL) {
1579 
1580 		return (USB_INVALID_PIPE);
1581 	}
1582 
1583 	return (usba_pipe_setup_func_call(dip,
1584 	    usba_sync_clear_feature, (usba_ph_impl_t *)ph,
1585 	    (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))),
1586 	    flags, cb, cb_arg));
1587 }
1588 
1589 
1590 static int
1591 usba_sync_clear_feature(dev_info_t *dip,
1592 	usba_ph_impl_t		*ph_impl,
1593 	usba_pipe_async_req_t	*req,
1594 	usb_flags_t		usb_flags)
1595 {
1596 	uint_t	n = (uint_t)((uintptr_t)(req->arg));
1597 	uint_t	type = ((uint_t)n >> 16) & 0xff;
1598 	uint_t	feature = ((uint_t)n >> 8) & 0xff;
1599 	uint_t	what = (uint_t)n & 0xff;
1600 	int	rval;
1601 	usba_device_t		*usba_device;
1602 	usba_pipe_handle_data_t *ph_data;
1603 	usba_ph_impl_t		*ph_im;
1604 	uchar_t			ep_index;
1605 	usb_ep_descr_t		*eptd;
1606 
1607 
1608 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1609 	    "usb_sync_clear_feature: "
1610 	    "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
1611 	    (void *)dip, (void *)ph_impl, type, feature, what, usb_flags);
1612 
1613 	rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
1614 	    feature, what, usb_flags);
1615 
1616 	/*
1617 	 * Reset data toggle to DATA0 for bulk and interrupt endpoint.
1618 	 * Data toggle synchronization is not supported for isochronous
1619 	 * transfer.Halt feature is not supported by control endpoint.
1620 	 *
1621 	 * From USB2.0 specification:
1622 	 * 1.Section 5.8.5 Bulk Transfer Data Sequences
1623 	 * Removal of the halt condition is achieved via software intervention
1624 	 * through a separate control pipe. This recovery will reset the data
1625 	 * toggle bit to DATA0 for the endpoint on both the host and the device.
1626 	 *
1627 	 * 2.Section 5.7.5 Interrupt Transfer Data Sequences
1628 	 * Removal of the halt condition is achieved via software intervention
1629 	 * through a separate control pipe. This recovery will reset the data
1630 	 * toggle bit to DATA0 for the endpoint on both the host and the device.
1631 	 *
1632 	 * 3.Section 9.4.5
1633 	 * If the condition causing a halt has been removed, clearing the Halt
1634 	 * feature via a ClearFeature(ENDPOINT_HALT) request results in the
1635 	 * endpoint no longer returning a STALL. For endpoints using data
1636 	 * toggle, regardless of whether an endpoint has the Halt feature set, a
1637 	 * ClearFeature(ENDPOINT_HALT) request always results in the data toggle
1638 	 * being reinitialized to DATA0.
1639 	 *
1640 	 */
1641 	if (rval == USB_SUCCESS && feature == 0) {
1642 		usba_device = usba_get_usba_device(dip);
1643 		ep_index = usb_get_ep_index((uint8_t)what);
1644 		ph_im = &usba_device->usb_ph_list[ep_index];
1645 		ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_im);
1646 		eptd = &ph_data->p_ep;
1647 		if ((eptd->bmAttributes & USB_EP_ATTR_MASK) ==
1648 		    USB_EP_ATTR_BULK || (eptd->bmAttributes &
1649 		    USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR)
1650 			usba_device->usb_hcdi_ops->
1651 			    usba_hcdi_pipe_reset_data_toggle(ph_data);
1652 	}
1653 
1654 	usba_release_ph_data(ph_impl);
1655 
1656 	return (rval);
1657 }
1658 
1659 
1660 /*
1661  * usb_async_req:
1662  *	function used to dispatch a request to the taskq
1663  *
1664  * Arguments:
1665  *	dip	- pointer to devinfo node
1666  *	func	- pointer to function issued by taskq
1667  *	flag	- USB_FLAGS_SLEEP mostly
1668  *
1669  * Return Values:
1670  *	USB_SUCCESS	- on doing a successful taskq invocation
1671  *	USB_FAILURE	- on failure
1672  *	USB_*		- refer to usbai.h
1673  */
1674 int
1675 usb_async_req(dev_info_t *dip,
1676 		void	(*func)(void *),
1677 		void	*arg,
1678 		usb_flags_t flag)
1679 {
1680 	int tq_flag;
1681 
1682 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1683 	    "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
1684 	    (void *)dip, (void *)func, arg, flag);
1685 
1686 	if ((dip == NULL) || (func == NULL)) {
1687 
1688 		return (USB_INVALID_ARGS);
1689 	}
1690 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1691 	if (flag & USB_FLAGS_NOQUEUE) {
1692 		tq_flag |= TQ_NOQUEUE;
1693 	}
1694 
1695 	if (taskq_dispatch(system_taskq, func, arg,
1696 	    tq_flag) == TASKQID_INVALID) {
1697 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1698 		    "usb_async_req: failure");
1699 
1700 		return (USB_FAILURE);
1701 	}
1702 
1703 	return (USB_SUCCESS);
1704 }
1705 
1706 /*
1707  * usba_async_ph_req:
1708  *	function used to dispatch a request to the ph taskq
1709  *
1710  * Arguments:
1711  *	ph_data	- pointer to pipe handle data
1712  *	func	- pointer to function issued by taskq
1713  *	flag	- USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
1714  *
1715  * Return Values:
1716  *	USB_SUCCESS	- on doing a successful taskq invocation
1717  *	USB_FAILURE	- on failure
1718  *	USB_*		- refer to usbai.h
1719  *
1720  * Note:
1721  *	If the caller specified  USB_FLAGS_NOSLEEP, it must be
1722  *	capable of reliably recovering from a failure return
1723  */
1724 int
1725 usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
1726 		void	(*func)(void *),
1727 		void	*arg,
1728 		usb_flags_t flag)
1729 {
1730 	int	tq_flag;
1731 	taskq_t *taskq;
1732 
1733 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1734 	    "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
1735 	    (void *)ph_data, (void *)func, arg, flag);
1736 
1737 	if (func == NULL) {
1738 
1739 		return (USB_INVALID_ARGS);
1740 	}
1741 
1742 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1743 
1744 	if (ph_data && ph_data->p_taskq) {
1745 		taskq = ph_data->p_taskq;
1746 	} else {
1747 		taskq = system_taskq;
1748 		tq_flag |= TQ_NOQUEUE;
1749 	}
1750 
1751 	if (taskq_dispatch(taskq, func, arg, tq_flag) == TASKQID_INVALID) {
1752 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1753 		    "usba_async_ph_req: failure");
1754 
1755 		return (USB_FAILURE);
1756 	}
1757 
1758 	return (USB_SUCCESS);
1759 }
1760 
1761 
1762 /*
1763  * utility functions to display CR, CB, return values
1764  */
1765 typedef struct conv_table {
1766 	int		what;
1767 	const char	*name;
1768 } conv_table_t;
1769 
1770 static const char *
1771 usba_get_name(conv_table_t *conv_table, int value)
1772 {
1773 	int i;
1774 	for (i = 0; conv_table[i].name != NULL; i++) {
1775 		if (conv_table[i].what == value) {
1776 
1777 			return (conv_table[i].name);
1778 		}
1779 	}
1780 
1781 	return ("unknown");
1782 }
1783 
1784 
1785 static conv_table_t cr_table[] = {
1786 	{ USB_CR_OK,		"<no errors detected>" },
1787 	{ USB_CR_CRC,		"<crc error detected>" },
1788 	{ USB_CR_BITSTUFFING,	"<Bit stuffing violation>" },
1789 	{ USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
1790 	{ USB_CR_STALL, 	"<Endpoint returned stall PID>" },
1791 	{ USB_CR_DEV_NOT_RESP,	"<Device not responding>" },
1792 	{ USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
1793 	{ USB_CR_UNEXP_PID,	"<Receive PID was not valid>" },
1794 	{ USB_CR_DATA_OVERRUN,	"<Data size exceeded>" },
1795 	{ USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
1796 	{ USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
1797 	{ USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
1798 	{ USB_CR_TIMEOUT,	"<Command timed out>" },
1799 	{ USB_CR_NOT_ACCESSED,	"<Not accessed by hardware>" },
1800 	{ USB_CR_NO_RESOURCES,	"<No resources>" },
1801 	{ USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
1802 	{ USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
1803 	{ USB_CR_PIPE_CLOSING,	"<Intr/ISOC IN pipe being closed>" },
1804 	{ USB_CR_PIPE_RESET,	"<Intr/ISOC IN pipe reset>" },
1805 	{ USB_CR_NOT_SUPPORTED, "<Command not supported>" },
1806 	{ USB_CR_FLUSHED,	"<Req was flushed>" },
1807 	{ USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
1808 	{ 0,			NULL }
1809 };
1810 
1811 const char *
1812 usb_str_cr(usb_cr_t cr)
1813 {
1814 	return (usba_get_name(cr_table, cr));
1815 }
1816 
1817 
1818 static conv_table_t cb_flags_table[] = {
1819 	{ USB_CB_NO_INFO,	"<callback processed>" },
1820 	{ USB_CB_STALL_CLEARED, "<stall cleared>" },
1821 	{ USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
1822 	{ USB_CB_PROTOCOL_STALL, "<protocol stall>" },
1823 	{ USB_CB_RESET_PIPE,	"<pipe reset>" },
1824 	{ USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
1825 	{ USB_CB_NO_RESOURCES,	"<no resources>" },
1826 	{ USB_CB_SUBMIT_FAILED, "<submit failed>" },
1827 	{ USB_CB_INTR_CONTEXT,	"<Callback executing in interrupt context>" },
1828 	{ 0,			NULL }
1829 };
1830 
1831 /*ARGSUSED*/
1832 char *
1833 usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
1834 {
1835 	int i;
1836 	buffer[0] = '\0';
1837 	if (cb_flags == USB_CB_NO_INFO) {
1838 		(void) strncpy(buffer, cb_flags_table[0].name, length);
1839 	} else {
1840 		for (i = 0; cb_flags_table[i].name != NULL; i++) {
1841 			if (cb_flags & cb_flags_table[i].what) {
1842 				(void) strncpy(&buffer[strlen(buffer)],
1843 				    cb_flags_table[0].name,
1844 				    length - strlen(buffer) - 1);
1845 			}
1846 		}
1847 	}
1848 
1849 	return (buffer);
1850 }
1851 
1852 
1853 static conv_table_t pipe_state_table[] = {
1854 	{ USB_PIPE_STATE_CLOSED,	"<closed>" },
1855 	{ USB_PIPE_STATE_IDLE,		"<idle>" },
1856 	{ USB_PIPE_STATE_ACTIVE,	"<active>" },
1857 	{ USB_PIPE_STATE_ERROR,		"<error>" },
1858 	{ USB_PIPE_STATE_CLOSING,	"<closing>" },
1859 	{ 0,				NULL }
1860 };
1861 
1862 const char *
1863 usb_str_pipe_state(usb_pipe_state_t state)
1864 {
1865 	return (usba_get_name(pipe_state_table, state));
1866 }
1867 
1868 
1869 static conv_table_t dev_state[] = {
1870 	{ USB_DEV_ONLINE,	"<online>" },
1871 	{ USB_DEV_DISCONNECTED,	"<disconnected>" },
1872 	{ USB_DEV_SUSPENDED,	"<suspended>" },
1873 	{ USB_DEV_PWRED_DOWN,	"<powered down>" },
1874 	{ 0,			NULL }
1875 };
1876 
1877 const char *
1878 usb_str_dev_state(int state)
1879 {
1880 	return (usba_get_name(dev_state, state));
1881 }
1882 
1883 
1884 static conv_table_t rval_table[] = {
1885 	{ USB_SUCCESS,		"<success>" },
1886 	{ USB_FAILURE,		"<failure>" },
1887 	{ USB_NO_RESOURCES,	"<no resources>" },
1888 	{ USB_NO_BANDWIDTH,	"<no bandwidth>" },
1889 	{ USB_NOT_SUPPORTED,	"<not supported>" },
1890 	{ USB_PIPE_ERROR,	"<pipe error>" },
1891 	{ USB_INVALID_PIPE,	"<invalid pipe>" },
1892 	{ USB_NO_FRAME_NUMBER,	"<no frame number>" },
1893 	{ USB_INVALID_START_FRAME, "<invalid frame>" },
1894 	{ USB_HC_HARDWARE_ERROR, "<hw error>" },
1895 	{ USB_INVALID_REQUEST,	"<invalid request>" },
1896 	{ USB_INVALID_CONTEXT,	"<invalid context>" },
1897 	{ USB_INVALID_VERSION,	"<invalid version>" },
1898 	{ USB_INVALID_ARGS,	"<invalid args>" },
1899 	{ USB_INVALID_PERM,	"<invalid perms>" },
1900 	{ USB_BUSY,		"<busy>" },
1901 	{ 0,			NULL }
1902 };
1903 
1904 const char *
1905 usb_str_rval(int rval)
1906 {
1907 	return (usba_get_name(rval_table, rval));
1908 }
1909 
1910 
1911 /*
1912  * function to convert USB return values to close errno
1913  */
1914 static struct usb_rval2errno_entry {
1915 	int	rval;
1916 	int	Errno;
1917 } usb_rval2errno_table[] = {
1918 	{ USB_SUCCESS,			0	},
1919 	{ USB_FAILURE,			EIO	},
1920 	{ USB_NO_RESOURCES,		ENOMEM	},
1921 	{ USB_NO_BANDWIDTH,		EAGAIN	},
1922 	{ USB_NOT_SUPPORTED,		ENOTSUP },
1923 	{ USB_PIPE_ERROR,		EIO	},
1924 	{ USB_INVALID_PIPE,		EINVAL	},
1925 	{ USB_NO_FRAME_NUMBER,		EINVAL	},
1926 	{ USB_INVALID_START_FRAME,	EINVAL	},
1927 	{ USB_HC_HARDWARE_ERROR,	EIO	},
1928 	{ USB_INVALID_REQUEST,		EINVAL	},
1929 	{ USB_INVALID_CONTEXT,		EINVAL	},
1930 	{ USB_INVALID_VERSION,		EINVAL	},
1931 	{ USB_INVALID_ARGS,		EINVAL	},
1932 	{ USB_INVALID_PERM,		EACCES	},
1933 	{ USB_BUSY,			EBUSY	},
1934 };
1935 
1936 #define	USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
1937 			sizeof (struct usb_rval2errno_entry))
1938 int
1939 usb_rval2errno(int rval)
1940 {
1941 	int i;
1942 
1943 	for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
1944 		if (usb_rval2errno_table[i].rval == rval) {
1945 
1946 			return (usb_rval2errno_table[i].Errno);
1947 		}
1948 	}
1949 
1950 	return (EIO);
1951 }
1952 
1953 
1954 /*
1955  * serialization
1956  */
1957 usb_serialization_t
1958 usb_init_serialization(
1959 	dev_info_t	*dip,
1960 	uint_t		flag)
1961 {
1962 	usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
1963 	    sizeof (usba_serialization_impl_t), KM_SLEEP);
1964 	usba_device_t	*usba_device;
1965 	ddi_iblock_cookie_t cookie = NULL;
1966 
1967 	if (dip) {
1968 		usba_device = usba_get_usba_device(dip);
1969 		cookie = usba_hcdi_get_hcdi(
1970 		    usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
1971 	}
1972 	impl_tokenp->s_dip = dip;
1973 	impl_tokenp->s_flag = flag;
1974 	mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
1975 	cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
1976 
1977 	return ((usb_serialization_t)impl_tokenp);
1978 }
1979 
1980 
1981 void
1982 usb_fini_serialization(
1983 	usb_serialization_t tokenp)
1984 {
1985 	usba_serialization_impl_t *impl_tokenp;
1986 
1987 	if (tokenp) {
1988 		impl_tokenp = (usba_serialization_impl_t *)tokenp;
1989 		ASSERT(impl_tokenp->s_count == 0);
1990 		cv_destroy(&impl_tokenp->s_cv);
1991 		mutex_destroy(&impl_tokenp->s_mutex);
1992 		kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
1993 	}
1994 }
1995 
1996 
1997 /*
1998  * usb_serialize_access() permits single threaded access.
1999  *
2000  * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
2001  * it is reentrant with respect to thread. The thread must
2002  * hold and release the same number of times.
2003  *
2004  * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
2005  * it is not reentrant by the same thread. It is something like
2006  * a semaphore.
2007  */
2008 int
2009 usb_serialize_access(
2010 	usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
2011 {
2012 	int			rval = 1;	/* Must be initialized > 0 */
2013 	clock_t			abs_timeout = 0;
2014 	usba_serialization_impl_t *impl_tokenp;
2015 
2016 	impl_tokenp = (usba_serialization_impl_t *)tokenp;
2017 
2018 	/*
2019 	 * Convert delta timeout in ms to absolute timeout in ticks, if used.
2020 	 */
2021 	if ((how_to_wait == USB_TIMEDWAIT) ||
2022 	    (how_to_wait == USB_TIMEDWAIT_SIG)) {
2023 		/* Convert timeout arg (in ms) to hz */
2024 		abs_timeout = ddi_get_lbolt() +
2025 		    drv_usectohz(delta_timeout * 1000);
2026 	}
2027 
2028 	/* Get mutex after calc abs time, to count time waiting for mutex. */
2029 	mutex_enter(&impl_tokenp->s_mutex);
2030 
2031 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2032 	    "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
2033 	    "flg=0x%x, abs_tmo=0x%lx",
2034 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2035 	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread,
2036 	    how_to_wait, abs_timeout);
2037 
2038 	if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
2039 	    impl_tokenp->s_thread != curthread) {
2040 
2041 		/*
2042 		 * There are three ways to break out of the loop:
2043 		 * 1) Condition met (s_count == 0) - higher prio test
2044 		 * 2) kill(2) signal received (rval == 0)
2045 		 * 3) timeout occurred (rval == -1)
2046 		 * If condition met, whether or not signal or timeout occurred
2047 		 * take access.  If condition not met, check other exit means.
2048 		 */
2049 		while (impl_tokenp->s_count != 0) {
2050 
2051 			/* cv_timedwait* returns -1 on timeout. */
2052 			/* cv_wait*_sig returns 0 on (kill(2)) signal. */
2053 			if (rval <= 0) {
2054 				mutex_exit(&impl_tokenp->s_mutex);
2055 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
2056 				    usbai_log_handle,
2057 				    "usb_serialize_access: "
2058 				    "tok=0x%p exit due to %s",
2059 				    (void *)impl_tokenp,
2060 				    ((rval == 0) ? "signal" : "timeout"));
2061 
2062 				return (rval);
2063 			}
2064 
2065 			switch (how_to_wait) {
2066 			default:
2067 				how_to_wait = USB_WAIT;
2068 				/* FALLTHROUGH */
2069 			case USB_WAIT:
2070 				cv_wait(&impl_tokenp->s_cv,
2071 				    &impl_tokenp->s_mutex);
2072 				break;
2073 			case USB_WAIT_SIG:
2074 				rval = cv_wait_sig(&impl_tokenp->s_cv,
2075 				    &impl_tokenp->s_mutex);
2076 				break;
2077 			case USB_TIMEDWAIT:
2078 				rval = cv_timedwait(&impl_tokenp->s_cv,
2079 				    &impl_tokenp->s_mutex, abs_timeout);
2080 				break;
2081 			case USB_TIMEDWAIT_SIG:
2082 				rval = cv_timedwait_sig(&impl_tokenp->s_cv,
2083 				    &impl_tokenp->s_mutex, abs_timeout);
2084 				break;
2085 			}
2086 		}
2087 
2088 		impl_tokenp->s_thread = curthread;
2089 	}
2090 	impl_tokenp->s_count++;
2091 
2092 	ASSERT(!(impl_tokenp->s_count > 1 &&
2093 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
2094 
2095 	mutex_exit(&impl_tokenp->s_mutex);
2096 
2097 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2098 	    "usb_serialize_access exit: tok=0x%p thr=0x%p", (void *)impl_tokenp,
2099 	    (void *)curthread);
2100 
2101 	return (1);
2102 }
2103 
2104 
2105 /*ARGSUSED*/
2106 int
2107 usb_try_serialize_access(
2108 	usb_serialization_t tokenp, uint_t flag)
2109 {
2110 	usba_serialization_impl_t *impl_tokenp =
2111 	    (usba_serialization_impl_t *)tokenp;
2112 	mutex_enter(&impl_tokenp->s_mutex);
2113 
2114 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2115 	    "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2116 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2117 	    impl_tokenp->s_count, (void *)curthread);
2118 
2119 	/*
2120 	 * If lock is not taken (s_count is 0), take it.
2121 	 * If lock is already taken, the thread is owner and lock
2122 	 * is reentrant, take it.
2123 	 * Otherwise, fail the access.
2124 	 */
2125 	if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
2126 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
2127 		impl_tokenp->s_thread = curthread;
2128 		impl_tokenp->s_count++;
2129 
2130 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2131 		    "usb_try_serialize_access success: tok=0x%p",
2132 		    (void *)impl_tokenp);
2133 		mutex_exit(&impl_tokenp->s_mutex);
2134 
2135 		return (USB_SUCCESS);
2136 	}
2137 
2138 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2139 	    "usb_try_serialize_access failed: "
2140 	    "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2141 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2142 	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread);
2143 
2144 	mutex_exit(&impl_tokenp->s_mutex);
2145 
2146 	return (USB_FAILURE);
2147 }
2148 
2149 
2150 void
2151 usb_release_access(
2152 	usb_serialization_t tokenp)
2153 {
2154 	usba_serialization_impl_t *impl_tokenp =
2155 	    (usba_serialization_impl_t *)tokenp;
2156 	mutex_enter(&impl_tokenp->s_mutex);
2157 
2158 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2159 	    "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
2160 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2161 	    impl_tokenp->s_count, (void *)curthread);
2162 
2163 	ASSERT(impl_tokenp->s_count > 0);
2164 
2165 	if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
2166 		if (impl_tokenp->s_thread != curthread) {
2167 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2168 			    "usb_release_access: release from wrong thread");
2169 		}
2170 		ASSERT(impl_tokenp->s_thread == curthread);
2171 	}
2172 
2173 	if (--impl_tokenp->s_count == 0) {
2174 		impl_tokenp->s_thread = NULL;
2175 		cv_broadcast(&impl_tokenp->s_cv);
2176 	}
2177 	mutex_exit(&impl_tokenp->s_mutex);
2178 }
2179 
2180 
2181 /*
2182  * usb_fail_checkpoint:
2183  *	fail checkpoint as driver/device could not be quiesced
2184  */
2185 /*ARGSUSED*/
2186 void
2187 usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
2188 {
2189 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2190 
2191 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2192 	    "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
2193 	    ddi_get_instance(dip));
2194 
2195 	mutex_enter(&usba_device->usb_mutex);
2196 	usba_device->usb_no_cpr++;
2197 	mutex_exit(&usba_device->usb_mutex);
2198 }
2199 
2200 
2201 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
2202 _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
2203 /*
2204  * usba_mk_mctl:
2205  *	create a USB style M_CTL message, given an iocblk and a buffer
2206  *	returns mblk_t * on success, NULL on failure
2207  */
2208 mblk_t *
2209 usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
2210 {
2211 	mblk_t *bp1, *bp2;
2212 
2213 	if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
2214 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2215 		*((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
2216 		bp1->b_datap->db_type = M_CTL;
2217 		bp1->b_wptr += sizeof (struct iocblk);
2218 		if (buf != NULL) {
2219 			if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
2220 				bp1->b_cont = bp2;
2221 				bcopy(buf, bp2->b_datap->db_base, len);
2222 				bp2->b_wptr += len;
2223 			} else {
2224 				freemsg(bp1);
2225 				bp1 = NULL;
2226 			}
2227 		}
2228 	}
2229 
2230 	return (bp1);
2231 }
2232 
2233 
2234 #ifdef ALLOCB_TEST
2235 #undef	allocb
2236 mblk_t *
2237 usba_test_allocb(size_t size, uint_t pri)
2238 {
2239 	if (ddi_get_lbolt() & 0x1) {
2240 
2241 		return (NULL);
2242 	} else {
2243 
2244 		return (allocb(size, pri));
2245 	}
2246 }
2247 #endif
2248 
2249 
2250 /*
2251  * usb common power management for usb_mid, usb_ia and maybe other simple
2252  * drivers.
2253  */
2254 
2255 /*
2256  * functions to handle power transition for OS levels 0 -> 3
2257  */
2258 static int
2259 usb_common_pwrlvl0(dev_info_t *dip, uint8_t *pm, int *dev_state)
2260 {
2261 	int	rval;
2262 
2263 	switch (*dev_state) {
2264 	case USB_DEV_ONLINE:
2265 		/* Issue USB D3 command to the device here */
2266 		rval = usb_set_device_pwrlvl3(dip);
2267 		ASSERT(rval == USB_SUCCESS);
2268 
2269 		*dev_state = USB_DEV_PWRED_DOWN;
2270 		*pm = USB_DEV_OS_PWR_OFF;
2271 		/* FALLTHRU */
2272 	case USB_DEV_DISCONNECTED:
2273 	case USB_DEV_SUSPENDED:
2274 		/* allow a disconnected/cpr'ed device to go to low pwr */
2275 
2276 		return (USB_SUCCESS);
2277 	case USB_DEV_PWRED_DOWN:
2278 	default:
2279 		return (USB_FAILURE);
2280 	}
2281 }
2282 
2283 
2284 /* ARGSUSED */
2285 static int
2286 usb_common_pwrlvl1(dev_info_t *dip, uint8_t *pm, int *dev_state)
2287 {
2288 	int	rval;
2289 
2290 	/* Issue USB D2 command to the device here */
2291 	rval = usb_set_device_pwrlvl2(dip);
2292 	ASSERT(rval == USB_SUCCESS);
2293 
2294 	return (USB_FAILURE);
2295 }
2296 
2297 
2298 /* ARGSUSED */
2299 static int
2300 usb_common_pwrlvl2(dev_info_t *dip, uint8_t *pm, int *dev_state)
2301 {
2302 	int	rval;
2303 
2304 	/* Issue USB D1 command to the device here */
2305 	rval = usb_set_device_pwrlvl1(dip);
2306 	ASSERT(rval == USB_SUCCESS);
2307 
2308 	return (USB_FAILURE);
2309 }
2310 
2311 
2312 static int
2313 usb_common_pwrlvl3(dev_info_t *dip, uint8_t *pm, int *dev_state)
2314 {
2315 	int	rval;
2316 
2317 	switch (*dev_state) {
2318 	case USB_DEV_PWRED_DOWN:
2319 		/* Issue USB D0 command to the device here */
2320 		rval = usb_set_device_pwrlvl0(dip);
2321 		ASSERT(rval == USB_SUCCESS);
2322 
2323 		*dev_state = USB_DEV_ONLINE;
2324 		*pm = USB_DEV_OS_FULL_PWR;
2325 
2326 		/* FALLTHRU */
2327 	case USB_DEV_ONLINE:
2328 		/* we are already in full power */
2329 
2330 		/* FALLTHRU */
2331 	case USB_DEV_DISCONNECTED:
2332 	case USB_DEV_SUSPENDED:
2333 		/* allow a disconnected/cpr'ed device to go to low power */
2334 
2335 		return (USB_SUCCESS);
2336 	default:
2337 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2338 		    "usb_common_pwrlvl3: Illegal state (%s)",
2339 		    usb_str_dev_state(*dev_state));
2340 
2341 		return (USB_FAILURE);
2342 	}
2343 }
2344 
2345 /* power management */
2346 int
2347 usba_common_power(dev_info_t *dip, uint8_t *pm, int *dev_state, int level)
2348 {
2349 	int rval = DDI_FAILURE;
2350 
2351 	switch (level) {
2352 	case USB_DEV_OS_PWR_OFF:
2353 		rval = usb_common_pwrlvl0(dip, pm, dev_state);
2354 		break;
2355 	case USB_DEV_OS_PWR_1:
2356 		rval = usb_common_pwrlvl1(dip, pm, dev_state);
2357 		break;
2358 	case USB_DEV_OS_PWR_2:
2359 		rval = usb_common_pwrlvl2(dip, pm, dev_state);
2360 		break;
2361 	case USB_DEV_OS_FULL_PWR:
2362 		rval = usb_common_pwrlvl3(dip, pm, dev_state);
2363 		break;
2364 	}
2365 
2366 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2367 }
2368 
2369 /*
2370  * register and unregister for events from our parent for usb_mid and usb_ia
2371  * and maybe other nexus driver.
2372  *
2373  * Note: The cookie fields in usba_device structure is not used. They are
2374  * used/shared by children.
2375  */
2376 void
2377 usba_common_register_events(dev_info_t *dip, uint_t if_num,
2378 	void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *))
2379 {
2380 	int rval;
2381 	usba_evdata_t *evdata;
2382 	ddi_eventcookie_t cookie;
2383 
2384 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2385 	    "usb_common_register_events:");
2386 
2387 	evdata = usba_get_evdata(dip);
2388 
2389 	/* get event cookie, discard level and icookie for now */
2390 	rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
2391 	    &cookie);
2392 
2393 	if (rval == DDI_SUCCESS) {
2394 		rval = ddi_add_event_handler(dip,
2395 		    cookie, event_cb, NULL, &evdata->ev_rm_cb_id);
2396 
2397 		if (rval != DDI_SUCCESS) {
2398 
2399 			goto fail;
2400 		}
2401 	}
2402 	rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
2403 	    &cookie);
2404 	if (rval == DDI_SUCCESS) {
2405 		rval = ddi_add_event_handler(dip, cookie, event_cb,
2406 		    NULL, &evdata->ev_ins_cb_id);
2407 
2408 		if (rval != DDI_SUCCESS) {
2409 
2410 			goto fail;
2411 		}
2412 	}
2413 	rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie);
2414 	if (rval == DDI_SUCCESS) {
2415 		rval = ddi_add_event_handler(dip,
2416 		    cookie, event_cb, NULL, &evdata->ev_suspend_cb_id);
2417 
2418 		if (rval != DDI_SUCCESS) {
2419 
2420 			goto fail;
2421 		}
2422 	}
2423 	rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie);
2424 	if (rval == DDI_SUCCESS) {
2425 		rval = ddi_add_event_handler(dip, cookie, event_cb, NULL,
2426 		    &evdata->ev_resume_cb_id);
2427 
2428 		if (rval != DDI_SUCCESS) {
2429 
2430 			goto fail;
2431 		}
2432 	}
2433 
2434 	return;
2435 
2436 
2437 fail:
2438 	usba_common_unregister_events(dip, if_num);
2439 
2440 }
2441 
2442 void
2443 usba_common_unregister_events(dev_info_t *dip, uint_t if_num)
2444 {
2445 	usba_evdata_t	*evdata;
2446 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2447 	int i;
2448 
2449 	evdata = usba_get_evdata(dip);
2450 
2451 	if (evdata->ev_rm_cb_id != NULL) {
2452 		(void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
2453 		evdata->ev_rm_cb_id = NULL;
2454 	}
2455 
2456 	if (evdata->ev_ins_cb_id != NULL) {
2457 		(void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
2458 		evdata->ev_ins_cb_id = NULL;
2459 	}
2460 
2461 	if (evdata->ev_suspend_cb_id != NULL) {
2462 		(void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
2463 		evdata->ev_suspend_cb_id = NULL;
2464 	}
2465 
2466 	if (evdata->ev_resume_cb_id != NULL) {
2467 		(void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
2468 		evdata->ev_resume_cb_id = NULL;
2469 	}
2470 
2471 	/* clear event data for children, required for cfgmadm unconfigure */
2472 	mutex_enter(&usba_device->usb_mutex);
2473 	if (usb_owns_device(dip)) {
2474 		usba_free_evdata(usba_device->usb_evdata);
2475 		usba_device->usb_evdata = NULL;
2476 		usba_device->rm_cookie = NULL;
2477 		usba_device->ins_cookie = NULL;
2478 		usba_device->suspend_cookie = NULL;
2479 		usba_device->resume_cookie = NULL;
2480 	} else {
2481 		for (i = 0; i < if_num; i++) {
2482 			usba_device->usb_client_flags[usba_get_ifno(dip) + i]
2483 			    &= ~USBA_CLIENT_FLAG_EV_CBS;
2484 		}
2485 	}
2486 	mutex_exit(&usba_device->usb_mutex);
2487 }
2488