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