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 2004 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 
566 	usba_device = usba_get_usba_device(dip);
567 
568 	/*
569 	 * default pipe is still open
570 	 * all other pipes should be closed
571 	 */
572 	for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
573 		if (usba_device->usb_ph_list[i].usba_ph_data) {
574 			ph_open_cnt++;
575 			break;
576 		}
577 	}
578 
579 	if (ph_open_cnt || ddi_get_child(dip)) {
580 		usba_release_ph_data(ph_impl);
581 
582 		return (USB_BUSY);
583 	}
584 
585 	size = usb_parse_cfg_descr(usba_device->usb_cfg_array[cfg_index],
586 			USB_CFG_DESCR_SIZE, &confdescr, USB_CFG_DESCR_SIZE);
587 
588 	/* hubdi should ensure that this descriptor is correct */
589 	ASSERT(size == USB_CFG_DESCR_SIZE);
590 
591 	/* set the configuration */
592 	rval = usb_pipe_sync_ctrl_xfer(dip, (usb_pipe_handle_t)ph_impl,
593 		USB_DEV_REQ_HOST_TO_DEV,
594 		USB_REQ_SET_CFG,
595 		confdescr.bConfigurationValue,
596 		0,
597 		0,
598 		NULL, 0,
599 		&completion_reason,
600 		&cb_flags, flags | USBA_FLAGS_PRIVILEGED | USB_FLAGS_SLEEP);
601 
602 	if (rval == USB_SUCCESS) {
603 		mutex_enter(&usba_device->usb_mutex);
604 		usba_device->usb_cfg_value = confdescr.bConfigurationValue;
605 		usba_device->usb_active_cfg_ndx = cfg_index;
606 		usba_device->usb_cfg = usba_device->usb_cfg_array[cfg_index];
607 		usba_device->usb_cfg_length = confdescr.wTotalLength;
608 		mutex_exit(&usba_device->usb_mutex);
609 
610 		/* update the configuration property */
611 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
612 			"configuration#", usba_device->usb_cfg_value);
613 	}
614 
615 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
616 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
617 
618 	usba_release_ph_data(ph_impl);
619 
620 	return (rval);
621 }
622 
623 
624 
625 /*
626  * usb_get_cfg():
627  *	get configuration value
628  *
629  * Arguments:
630  *	dip		- pointer to devinfo of the client
631  *	cfg_value	- current config value
632  *	flags		- none, always blocks
633  *
634  * Return Values:
635  *	USB_SUCCESS:	- config value was retrieved
636  *	USB_FAILURE:	- config value could not be retrieved
637  *	USB_*		- refer to usbai.h
638  */
639 int
640 usb_get_cfg(dev_info_t		*dip,
641 		uint_t		*cfgval,
642 		usb_flags_t	flags)
643 {
644 	int		rval;
645 	usb_cr_t	completion_reason;
646 	mblk_t		*data = NULL;
647 	usb_cb_flags_t	cb_flags;
648 	usb_pipe_handle_t ph;
649 
650 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
651 	    "usb_get_cfg: %s uf = 0x%x", ddi_node_name(dip), flags);
652 
653 	if ((cfgval == NULL) || (dip == NULL)) {
654 
655 		return (USB_INVALID_ARGS);
656 	}
657 
658 	ph = usba_get_dflt_pipe_handle(dip);
659 
660 	/*
661 	 * get the cfg value
662 	 */
663 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
664 		USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_DEV,
665 		USB_REQ_GET_CFG,
666 		0,
667 		0,
668 		1,		/* returns one byte of data */
669 		&data, 0,
670 		&completion_reason,
671 		&cb_flags, flags);
672 
673 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
674 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
675 
676 	if ((rval == USB_SUCCESS) && data &&
677 	    ((data->b_wptr - data->b_rptr) == 1)) {
678 		*cfgval = *(data->b_rptr);
679 	} else {
680 		*cfgval = 1;
681 		if (rval == USB_SUCCESS) {
682 			rval = USB_FAILURE;
683 		}
684 	}
685 
686 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
687 	    "usb_get_cfg: %s cfgval=%d", ddi_node_name(dip), *cfgval);
688 
689 	freemsg(data);
690 
691 	return (rval);
692 }
693 
694 
695 /*
696  * usb_get_current_cfgidx:
697  *	get current current config index
698  */
699 uint_t
700 usb_get_current_cfgidx(dev_info_t *dip)
701 {
702 	usba_device_t	*usba_device = usba_get_usba_device(dip);
703 	uint_t		ndx;
704 
705 	mutex_enter(&usba_device->usb_mutex);
706 	ndx = usba_device->usb_active_cfg_ndx;
707 	mutex_exit(&usba_device->usb_mutex);
708 
709 	return (ndx);
710 }
711 
712 
713 /*
714  * usb_get_if_number:
715  *	get usb interface number of current OS device node.
716  *
717  * Arguments:
718  *	dip		- pointer to devinfo of the client
719  *
720  * Return Values:
721  *	USB_COMBINED_NODE if the driver is responsible for the entire
722  *	    device and this dip doesn't correspond to a device node.
723  *	USB_DEVICE_NODE if the driver is responsible for the entire device
724  *	    and this dip corresponds to a device node.
725  *	interface number: otherwise.
726  */
727 int
728 usb_get_if_number(dev_info_t *dip)
729 {
730 	int interface_num;
731 	usba_device_t	*usba_device = usba_get_usba_device(dip);
732 	usb_dev_descr_t	*usb_dev_descr;
733 
734 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
735 	    "usb_get_if_number: dip = 0x%p", dip);
736 
737 	/* not quite right but we can't return a negative return value */
738 	if (dip == NULL) {
739 
740 		return (0);
741 	}
742 
743 	if (usba_device) {
744 		usb_dev_descr = usba_device->usb_dev_descr;
745 	} else {
746 
747 		return (0);
748 	}
749 
750 	interface_num = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
751 	    DDI_PROP_DONTPASS, "interface", USB_COMBINED_NODE);
752 
753 	if (interface_num == USB_COMBINED_NODE) {
754 		if (!(((usb_dev_descr->bDeviceClass == USB_CLASS_HUB) ||
755 		    (usb_dev_descr->bDeviceClass == 0)) &&
756 		    (usba_device->usb_n_cfgs == 1) &&
757 		    (usba_device->usb_n_ifs == 1))) {
758 			interface_num = USB_DEVICE_NODE;
759 		}
760 	}
761 
762 	return (interface_num);
763 }
764 
765 
766 boolean_t
767 usb_owns_device(dev_info_t *dip)
768 {
769 	int interface_num = usb_get_if_number(dip);
770 
771 	return (interface_num < 0 ? B_TRUE : B_FALSE);
772 }
773 
774 
775 uint8_t
776 usba_get_ifno(dev_info_t *dip)
777 {
778 	int interface_num = usb_get_if_number(dip);
779 
780 	return (interface_num < 0 ? 0 : interface_num);
781 }
782 
783 
784 /*
785  * usb_set_alt_if:
786  *	set the alternate interface number. Issues USB_REQ_SET_IF
787  *	This function will access the device
788  *
789  * Arguments:
790  *	dip		- pointer to devinfo of the client
791  *	if_number	- interface number
792  *	alt_number	- alternate interface number
793  *	flags		- USB_FLAGS_SLEEP:
794  *				wait for completion
795  *	cb		- if USB_FLAGS_SLEEP has not been specified
796  *			  this callback function will be called on
797  *			  completion. This callback may be NULL
798  *			  and no notification of completion will then
799  *			  be provided.
800  *	cb_arg		- 2nd argument to callback function.
801  *
802  *
803  * return values:
804  *	USB_SUCCESS	- alternate was set
805  *	USB_FAILURE	- alternate could not be set because pipes
806  *			  were still open or some access error occurred
807  *	USB_*		- refer to usbai.h
808  *
809  * Note:
810  *	we can't easily check if all pipes to endpoints for this interface
811  *	are closed since we don't have a map of which endpoints belong
812  *	to which interface. If we had this map, we would need to update
813  *	this on each alternative or configuration switch
814  */
815 int
816 usb_set_alt_if(dev_info_t	*dip,
817 		uint_t		interface,
818 		uint_t		alt_number,
819 		usb_flags_t	usb_flags,
820 		void		(*cb)(
821 					usb_pipe_handle_t ph,
822 					usb_opaque_t	arg,
823 					int		rval,
824 					usb_cb_flags_t	flags),
825 		usb_opaque_t	cb_arg)
826 {
827 	usb_pipe_handle_t	ph;
828 
829 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
830 	    "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
831 	    ddi_driver_name(dip), ddi_get_instance(dip),
832 	    interface, alt_number, usb_flags);
833 
834 	if (dip == NULL) {
835 
836 		return (USB_INVALID_ARGS);
837 	}
838 
839 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
840 
841 		return (USB_INVALID_CONTEXT);
842 	}
843 
844 	ph = usba_get_dflt_pipe_handle(dip);
845 	if (usba_hold_ph_data(ph) == NULL) {
846 
847 		return (USB_INVALID_PIPE);
848 	}
849 
850 	return (usba_pipe_setup_func_call(dip,
851 	    usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
852 	    (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
853 	    usb_flags, cb, cb_arg));
854 }
855 
856 
857 static int
858 usba_sync_set_alt_if(dev_info_t	*dip,
859 		usba_ph_impl_t	*ph_impl,
860 		usba_pipe_async_req_t	*request,
861 		usb_flags_t	flags)
862 {
863 	int		rval;
864 	usb_cr_t	completion_reason;
865 	usb_cb_flags_t	cb_flags;
866 	usb_opaque_t	arg = request->arg;
867 	int		interface = ((uintptr_t)arg >> 8) & 0xff;
868 	int		alt_number = (uintptr_t)arg & 0xff;
869 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
870 				(usb_pipe_handle_t)ph_impl);
871 
872 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
873 	    "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
874 	    "uf=0x%x", ddi_node_name(dip), interface,
875 	    alt_number, flags);
876 
877 	/* if we don't own the device, we must own the interface */
878 	if (!usb_owns_device(dip) &&
879 	    (interface != usb_get_if_number(dip))) {
880 		usba_release_ph_data(ph_data->p_ph_impl);
881 
882 		return (USB_INVALID_PERM);
883 	}
884 
885 	/* set the alternate setting */
886 	rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
887 		USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
888 		USB_REQ_SET_IF,
889 		alt_number,
890 		interface,
891 		0,
892 		NULL, 0,
893 		&completion_reason,
894 		&cb_flags, flags | USB_FLAGS_SLEEP);
895 
896 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
897 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
898 
899 	usba_release_ph_data(ph_data->p_ph_impl);
900 
901 	return (rval);
902 }
903 
904 
905 /*
906  * usb_get_alt_if:
907  *	get the alternate interface number. Issues USB_REQ_GET_IF
908  *	This function will access the device and block
909  *
910  * Arguments:
911  *	dip			- pointer to devinfo of the client
912  *	if_number	- interface number
913  *	alt_number	- alternate interface number
914  *	flags			- none but USB_FLAGS_SLEEP may be passed
915  *
916  * return values:
917  *	USB_SUCCESS:		alternate was set
918  *	USB_FAILURE:		alternate could not be set because pipes
919  *				were still open or some access error occurred
920  */
921 int
922 usb_get_alt_if(dev_info_t	*dip,
923 		uint_t		if_number,
924 		uint_t		*alt_number,
925 		usb_flags_t	flags)
926 {
927 	int		rval;
928 	usb_cr_t	completion_reason;
929 	mblk_t		*data = NULL;
930 	usb_cb_flags_t	cb_flags;
931 	usb_pipe_handle_t ph;
932 
933 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
934 	    "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
935 	    "uf = 0x%x", ddi_node_name(dip), if_number,
936 	    alt_number, flags);
937 
938 	if ((alt_number == NULL) || (dip == NULL)) {
939 
940 		return (USB_INVALID_ARGS);
941 	}
942 
943 	ph = usba_get_dflt_pipe_handle(dip);
944 
945 	/*
946 	 * get the alternate setting
947 	 */
948 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
949 		USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
950 		USB_REQ_GET_IF,
951 		0,
952 		if_number,
953 		1,		/* returns one byte of data */
954 		&data, 0,
955 		&completion_reason,
956 		&cb_flags, flags);
957 
958 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
959 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
960 
961 	if ((rval == USB_SUCCESS) && data &&
962 	    ((data->b_wptr - data->b_rptr) == 1)) {
963 		*alt_number = *(data->b_rptr);
964 	} else {
965 		*alt_number = 0;
966 		if (rval == USB_SUCCESS) {
967 			rval = USB_FAILURE;
968 		}
969 	}
970 
971 	freemsg(data);
972 
973 	return (rval);
974 }
975 
976 
977 /*
978  * usba_get_cfg_cloud:
979  *	Get descriptor cloud for a given configuration.
980  *
981  * Arguments:
982  *	dip			- pointer to devinfo of the client
983  *	default_ph		- default pipe handle
984  *	cfg			- which configuration to retrieve raw cloud of
985  *
986  * Returns:
987  *	on success: mblock containing the raw data.  Caller must free.
988  *	on failure: NULL
989  */
990 static mblk_t *
991 usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
992 {
993 	usb_cr_t	completion_reason;
994 	usb_cb_flags_t	cb_flags;
995 	usb_cfg_descr_t cfg_descr;
996 	mblk_t		*pdata = NULL;
997 
998 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
999 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1000 	    USB_REQ_GET_DESCR,
1001 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1002 	    0,
1003 	    USB_CFG_DESCR_SIZE,
1004 	    &pdata,
1005 	    0,
1006 	    &completion_reason,
1007 	    &cb_flags,
1008 	    0) != USB_SUCCESS) {
1009 
1010 		freemsg(pdata);
1011 
1012 		return (NULL);
1013 	}
1014 
1015 	(void) usb_parse_cfg_descr(pdata->b_rptr,
1016 	    pdata->b_wptr - pdata->b_rptr, &cfg_descr, USB_CFG_DESCR_SIZE);
1017 	freemsg(pdata);
1018 	pdata = NULL;
1019 
1020 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1021 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1022 	    USB_REQ_GET_DESCR,
1023 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1024 	    0,
1025 	    cfg_descr.wTotalLength,
1026 	    &pdata,
1027 	    0,
1028 	    &completion_reason,
1029 	    &cb_flags,
1030 	    0) != USB_SUCCESS) {
1031 
1032 		freemsg(pdata);
1033 
1034 		return (NULL);
1035 	}
1036 
1037 	return (pdata);
1038 }
1039 
1040 /*
1041  * usb_check_same_device:
1042  *	Check if the device connected to the port is the same as
1043  *	the previous device that was in the port.  The previous device is
1044  *	represented by the dip on record for the port.	Print a message
1045  *	if the device is different.  If device_string arg is not NULL, it is
1046  *	included in the message.  Can block.
1047  *
1048  * Arguments:
1049  *	dip			- pointer to devinfo of the client
1050  *	log_handle		- handle to which messages are logged
1051  *	log_level		- one of USB_LOG_*
1052  *	log_mask		- logging mask
1053  *	check_mask		- one mask containing things to check:
1054  *					USB_CHK_BASIC: empty mask;
1055  *						these checks are always done.
1056  *					USB_CHK_VIDPID:
1057  *						check vid, pid only.
1058  *					USB_CHK_SERIAL: check match on device
1059  *						serial number.
1060  *					USB_CHK_CFG: check all raw config
1061  *						clouds for a match.
1062  *				NOTE: descr length and content always checked
1063  *	device_string		- Device string to appear in error message
1064  *
1065  * return values:
1066  *	USB_SUCCESS:		same device
1067  *	USB_INVALID_VERSION	not same device
1068  *	USB_FAILURE:		Failure processing request
1069  *	USB_INVALID_ARG:	dip is invalid
1070  */
1071 int
1072 usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
1073     int log_level, int log_mask, uint_t check_mask, char *device_string)
1074 {
1075 	usb_dev_descr_t		usb_dev_descr;
1076 	usba_device_t		*usba_device;
1077 	mblk_t			*pdata = NULL;
1078 	uint16_t		length;
1079 	int			rval;
1080 	char			*buf;
1081 	usb_cr_t		completion_reason;
1082 	usb_cb_flags_t		cb_flags;
1083 	boolean_t		match = B_TRUE;
1084 	usb_pipe_handle_t	def_ph;
1085 
1086 	if (dip == NULL) {
1087 
1088 		return (USB_INVALID_ARGS);
1089 	}
1090 
1091 	usba_device = usba_get_usba_device(dip);
1092 	length = usba_device->usb_dev_descr->bLength;
1093 	def_ph = usba_get_dflt_pipe_handle(dip);
1094 	ASSERT(def_ph);
1095 
1096 	/* get the "new" device descriptor */
1097 	rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
1098 			USB_DEV_REQ_DEV_TO_HOST |
1099 				USB_DEV_REQ_TYPE_STANDARD,
1100 			USB_REQ_GET_DESCR,		/* bRequest */
1101 			USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
1102 			0,				/* wIndex */
1103 			length,				/* wLength */
1104 			&pdata, 0,
1105 			&completion_reason,
1106 			&cb_flags, USB_FLAGS_SLEEP);
1107 
1108 	if (rval != USB_SUCCESS) {
1109 		if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
1110 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
1111 			    "getting device descriptor failed (%d)", rval);
1112 			freemsg(pdata);
1113 
1114 			return (USB_FAILURE);
1115 		}
1116 	}
1117 
1118 	ASSERT(pdata != NULL);
1119 
1120 	(void) usb_parse_dev_descr(pdata->b_rptr,
1121 	    pdata->b_wptr - pdata->b_rptr, &usb_dev_descr,
1122 	    sizeof (usb_dev_descr_t));
1123 
1124 	freemsg(pdata);
1125 	pdata = NULL;
1126 
1127 	/* Always check the device descriptor length. */
1128 	if (usb_dev_descr.bLength != length) {
1129 		match = B_FALSE;
1130 	}
1131 
1132 	if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
1133 		match = (usba_device->usb_dev_descr->idVendor ==
1134 		    usb_dev_descr.idVendor) &&
1135 		    (usba_device->usb_dev_descr->idProduct ==
1136 		    usb_dev_descr.idProduct);
1137 	} else if (bcmp((char *)usba_device->usb_dev_descr,
1138 	    (char *)&usb_dev_descr, length) != 0) {
1139 		match = B_FALSE;
1140 	}
1141 
1142 	/* if requested & this device has a serial number check and compare */
1143 	if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
1144 	    (usba_device->usb_serialno_str != NULL)) {
1145 		buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1146 		if (usb_get_string_descr(dip, USB_LANG_ID,
1147 		    usb_dev_descr.iSerialNumber, buf,
1148 		    USB_MAXSTRINGLEN) == USB_SUCCESS) {
1149 			match =
1150 			    (strcmp(buf, usba_device->usb_serialno_str) == 0);
1151 		}
1152 		kmem_free(buf, USB_MAXSTRINGLEN);
1153 	}
1154 
1155 	if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) {
1156 
1157 		uint8_t num_cfgs = usb_dev_descr.bNumConfigurations;
1158 		uint8_t cfg;
1159 		mblk_t *cloud;
1160 
1161 		for (cfg = 0; cfg < num_cfgs; cfg++) {
1162 			cloud = usba_get_cfg_cloud(dip, def_ph, cfg);
1163 			if (cloud == NULL) {
1164 				USB_DPRINTF_L3(DPRINT_MASK_USBA,
1165 				    usbai_log_handle,
1166 				    "Could not retrieve config cloud for "
1167 				    "comparison");
1168 				break;
1169 			}
1170 
1171 			if (bcmp((char *)cloud->b_rptr,
1172 			    usba_device->usb_cfg_array[cfg],
1173 			    cloud->b_wptr - cloud->b_rptr) != 0) {
1174 				freemsg(cloud);
1175 				break;
1176 			}
1177 
1178 			freemsg(cloud);
1179 		}
1180 		if (cfg != num_cfgs) {
1181 			match = B_FALSE;
1182 		}
1183 	}
1184 
1185 	if (match == B_FALSE) {
1186 		boolean_t allocated_here = (device_string == NULL);
1187 		if (allocated_here) {
1188 			device_string =
1189 			    kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP);
1190 			(void) usba_get_mfg_prod_sn_str(dip, device_string,
1191 						USB_MAXSTRINGLEN);
1192 		}
1193 		if (device_string[0] != '\0') {
1194 			(void) usb_log(log_handle, log_level, log_mask,
1195 			    "Cannot access %s.	Please reconnect.",
1196 			    device_string);
1197 		} else {
1198 			(void) usb_log(log_handle, log_level, log_mask,
1199 			    "Device is not identical to the "
1200 			    "previous one this port.\n"
1201 			    "Please disconnect and reconnect");
1202 		}
1203 		if (allocated_here) {
1204 			kmem_free(device_string, USB_MAXSTRINGLEN);
1205 		}
1206 
1207 		return (USB_INVALID_VERSION);
1208 	}
1209 
1210 	return (USB_SUCCESS);
1211 }
1212 
1213 
1214 /*
1215  * usb_pipe_get_state:
1216  *	Return the state of the pipe
1217  *
1218  * Arguments:
1219  *	pipe_handle	- pipe_handle pointer
1220  *	pipe_state	- pointer to copy pipe state to
1221  *	flags:
1222  *		not used other than to check context
1223  *
1224  * Return Values:
1225  *	USB_SUCCESS	- port state returned
1226  *	USB_*		- refer to usbai.h
1227  */
1228 int
1229 usb_pipe_get_state(usb_pipe_handle_t	pipe_handle,
1230 	    usb_pipe_state_t	*pipe_state,
1231 	    usb_flags_t		usb_flags)
1232 {
1233 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1234 
1235 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1236 	    "usb_pipe_get_state: ph_data=0x%p uf=0x%x", ph_data, usb_flags);
1237 
1238 	if (pipe_state == NULL) {
1239 		if (ph_data) {
1240 			usba_release_ph_data(ph_data->p_ph_impl);
1241 		}
1242 
1243 		return (USB_INVALID_ARGS);
1244 	}
1245 
1246 	if (ph_data == NULL) {
1247 		*pipe_state = USB_PIPE_STATE_CLOSED;
1248 
1249 		return (USB_SUCCESS);
1250 	}
1251 
1252 	mutex_enter(&ph_data->p_mutex);
1253 	*pipe_state = usba_get_ph_state(ph_data);
1254 	mutex_exit(&ph_data->p_mutex);
1255 
1256 	usba_release_ph_data(ph_data->p_ph_impl);
1257 
1258 	return (USB_SUCCESS);
1259 }
1260 
1261 
1262 /*
1263  * usba_pipe_get_policy:
1264  *	Return a pipe's policy
1265  *
1266  * Arguments:
1267  *	pipe_handle	- pipe_handle pointer
1268  *
1269  * Return Values:
1270  *	On success: the pipe's policy
1271  *	On failure: NULL
1272  */
1273 usb_pipe_policy_t
1274 *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)
1275 {
1276 	usb_pipe_policy_t *pp = NULL;
1277 
1278 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1279 
1280 	if (ph_data) {
1281 		pp = &ph_data->p_policy;
1282 
1283 		usba_release_ph_data(ph_data->p_ph_impl);
1284 	}
1285 
1286 	return (pp);
1287 }
1288 
1289 
1290 /*
1291  * usb_ep_num:
1292  *	Return the endpoint number for a given pipe handle
1293  *
1294  * Arguments:
1295  *	pipe_handle	- pipe_handle pointer
1296  *
1297  * Return Values:
1298  *	endpoint number
1299  */
1300 int
1301 usb_ep_num(usb_pipe_handle_t pipe_handle)
1302 {
1303 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1304 	int ep_num;
1305 
1306 	if (ph_data == NULL) {
1307 
1308 		return (USB_INVALID_PIPE);
1309 	}
1310 
1311 	mutex_enter(&ph_data->p_mutex);
1312 	ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
1313 	mutex_exit(&ph_data->p_mutex);
1314 
1315 	usba_release_ph_data(ph_data->p_ph_impl);
1316 
1317 	return (ep_num);
1318 }
1319 
1320 
1321 /*
1322  * usb_get_status
1323  *	Issues USB_REQ_GET_STATUS to device/endpoint/interface
1324  *	and report in "status" arg.
1325  *
1326  *	status reported for a "device" is
1327  *		RemoteWakeup enabled
1328  *		SelfPowered device?
1329  *
1330  *	status reported for an "interface" is NONE.
1331  *	status reported for an "endpoint" is
1332  *		HALT set (device STALLED?)
1333  *
1334  * Arguments:
1335  *	dip	- pointer to devinfo of the client
1336  *	ph	- pipe handle
1337  *	type	- bmRequestType to be used
1338  *	what	- 0 for device, otherwise interface or ep number
1339  *	status	- user supplied pointer for storing the status
1340  *	flags	- USB_FLAGS_SLEEP (mandatory)
1341  *
1342  * Return Values:
1343  *	valid usb_status_t	or USB_FAILURE
1344  */
1345 int
1346 usb_get_status(dev_info_t		*dip,
1347 		usb_pipe_handle_t	ph,
1348 		uint_t			type,	/* bmRequestType */
1349 		uint_t			what,	/* 0, interface, ept number */
1350 		uint16_t		*status,
1351 		usb_flags_t		flags)
1352 {
1353 	int		rval;
1354 	usb_cr_t	completion_reason;
1355 	mblk_t		*data = NULL;
1356 	usb_cb_flags_t	cb_flags;
1357 
1358 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1359 	    "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
1360 	    type, what, flags);
1361 
1362 	if ((status == NULL) || (dip == NULL)) {
1363 
1364 		return (USB_INVALID_ARGS);
1365 	}
1366 	if (ph == NULL) {
1367 
1368 		return (USB_INVALID_PIPE);
1369 	}
1370 
1371 	type |= USB_DEV_REQ_DEV_TO_HOST;
1372 
1373 	/* get the status */
1374 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1375 		type,
1376 		USB_REQ_GET_STATUS,
1377 		0,
1378 		what,
1379 		USB_GET_STATUS_LEN,	/* status is fixed 2 bytes long */
1380 		&data, 0,
1381 		&completion_reason, &cb_flags, flags);
1382 
1383 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1384 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1385 
1386 	if ((rval == USB_SUCCESS) && data &&
1387 	    ((data->b_wptr - data->b_rptr) == USB_GET_STATUS_LEN)) {
1388 		*status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
1389 	} else {
1390 		*status = 0;
1391 		if (rval == USB_SUCCESS) {
1392 			rval = USB_FAILURE;
1393 		}
1394 	}
1395 
1396 	freemsg(data);
1397 
1398 	return (rval);
1399 }
1400 
1401 
1402 /*
1403  * usb_clear_feature:
1404  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1405  *
1406  * Arguments:
1407  *	dip		- pointer to devinfo of the client
1408  *	ph		- pipe handle pointer
1409  *	type		- bmRequestType to be used
1410  *	feature		- feature to be cleared
1411  *	what		- 0 for device, otherwise interface or ep number
1412  *	flags		- none (but will sleep)
1413  *
1414  * Return Values:
1415  *	USB_SUCCESS	- on doing a successful clear feature
1416  *	USB_FAILURE	- on failure
1417  *	USB_*		- refer to usbai.h
1418  */
1419 int
1420 usb_clear_feature(dev_info_t		*dip,
1421 		usb_pipe_handle_t	ph,
1422 		uint_t			type,	/* bmRequestType */
1423 		uint_t			feature,
1424 		uint_t			what,	/* 0, interface, ept number */
1425 		usb_flags_t		flags)
1426 {
1427 	int		rval;
1428 	usb_cr_t	completion_reason;
1429 	usb_cb_flags_t	cb_flags;
1430 
1431 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1432 	    "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1433 	    "uf = 0x%x", type, feature, what, flags);
1434 
1435 	if (dip == NULL) {
1436 
1437 		return (USB_INVALID_ARGS);
1438 	}
1439 	if (ph == NULL) {
1440 
1441 		return (USB_INVALID_PIPE);
1442 	}
1443 
1444 	/* issue Clear feature */
1445 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1446 		type,
1447 		USB_REQ_CLEAR_FEATURE,
1448 		feature,
1449 		what,
1450 		0,
1451 		NULL, 0,
1452 		&completion_reason,
1453 		&cb_flags, flags | USB_FLAGS_SLEEP);
1454 
1455 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1456 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1457 
1458 	return (rval);
1459 }
1460 
1461 
1462 /*
1463  * usb_clr_feature:
1464  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1465  *
1466  * Arguments:
1467  *	dip		- pointer to devinfo of the client
1468  *	type		- bmRequestType to be used
1469  *	feature		- feature to be cleared
1470  *	what		- 0 for device, otherwise interface or ep number
1471  *	flags		- USB_FLAGS_SLEEP:
1472  *				wait for completion
1473  *	cb		- if USB_FLAGS_SLEEP has not been specified
1474  *			  this callback function will be called on
1475  *			  completion. This callback may be NULL
1476  *			  and no notification of completion will then
1477  *			  be provided.
1478  *	cb_arg		- 2nd argument to callback function.
1479  *
1480  *
1481  * Return Values:
1482  *	USB_SUCCESS	- on doing a successful clear feature
1483  *	USB_FAILURE	- on failure
1484  *	USB_*		- refer to usbai.h
1485  */
1486 int
1487 usb_clr_feature(
1488 		dev_info_t	*dip,
1489 		uint_t		type,	/* bmRequestType */
1490 		uint_t		feature,
1491 		uint_t		what,	/* 0, interface, ept number */
1492 		usb_flags_t	flags,
1493 		void		(*cb)(
1494 					usb_pipe_handle_t ph,
1495 					usb_opaque_t	arg,
1496 					int		rval,
1497 					usb_cb_flags_t	flags),
1498 		usb_opaque_t	cb_arg)
1499 {
1500 	usb_pipe_handle_t ph;
1501 
1502 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1503 	    "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1504 	    "uf = 0x%x", type, feature, what, flags);
1505 
1506 	if (dip == NULL) {
1507 
1508 		return (USB_INVALID_ARGS);
1509 	}
1510 
1511 	if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1512 
1513 		return (USB_INVALID_CONTEXT);
1514 	}
1515 
1516 	ph = usba_get_dflt_pipe_handle(dip);
1517 	if (usba_hold_ph_data(ph) == NULL) {
1518 
1519 		return (USB_INVALID_PIPE);
1520 	}
1521 
1522 	return (usba_pipe_setup_func_call(dip,
1523 	    usba_sync_clear_feature, (usba_ph_impl_t *)ph,
1524 	    (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))),
1525 	    flags, cb, cb_arg));
1526 }
1527 
1528 
1529 static int
1530 usba_sync_clear_feature(dev_info_t *dip,
1531 	usba_ph_impl_t		*ph_impl,
1532 	usba_pipe_async_req_t	*req,
1533 	usb_flags_t 		usb_flags)
1534 {
1535 	uint_t	n = (uint_t)((uintptr_t)(req->arg));
1536 	uint_t	type = ((uint_t)n >> 16) & 0xff;
1537 	uint_t	feature = ((uint_t)n >> 8) & 0xff;
1538 	uint_t	what = (uint_t)n & 0xff;
1539 	int 	rval;
1540 
1541 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1542 	    "usb_sync_clear_feature: "
1543 	    "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
1544 	    dip, ph_impl, type, feature, what, usb_flags);
1545 
1546 	rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
1547 					feature, what, usb_flags);
1548 
1549 	usba_release_ph_data(ph_impl);
1550 
1551 	return (rval);
1552 }
1553 
1554 
1555 /*
1556  * usb_async_req:
1557  *	function used to dispatch a request to the taskq
1558  *
1559  * Arguments:
1560  *	dip	- pointer to devinfo node
1561  *	func	- pointer to function issued by taskq
1562  *	flag	- USB_FLAGS_SLEEP mostly
1563  *
1564  * Return Values:
1565  *	USB_SUCCESS	- on doing a successful taskq invocation
1566  *	USB_FAILURE	- on failure
1567  *	USB_*		- refer to usbai.h
1568  */
1569 int
1570 usb_async_req(dev_info_t *dip,
1571 		void	(*func)(void *),
1572 		void	*arg,
1573 		usb_flags_t flag)
1574 {
1575 	int tq_flag;
1576 
1577 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1578 	    "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
1579 	    dip, func, arg, flag);
1580 
1581 	if ((dip == NULL) || (func == NULL)) {
1582 
1583 		return (USB_INVALID_ARGS);
1584 	}
1585 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1586 	if (flag & USB_FLAGS_NOQUEUE) {
1587 		tq_flag |= TQ_NOQUEUE;
1588 	}
1589 
1590 	if (!taskq_dispatch(system_taskq, func, (void *)arg,
1591 	    tq_flag)) {
1592 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1593 		    "usb_async_req: failure");
1594 
1595 		return (USB_FAILURE);
1596 	}
1597 
1598 	return (USB_SUCCESS);
1599 }
1600 
1601 /*
1602  * usba_async_ph_req:
1603  *	function used to dispatch a request to the ph taskq
1604  *
1605  * Arguments:
1606  *	ph_data	- pointer to pipe handle data
1607  *	func	- pointer to function issued by taskq
1608  *	flag	- USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
1609  *
1610  * Return Values:
1611  *	USB_SUCCESS	- on doing a successful taskq invocation
1612  *	USB_FAILURE	- on failure
1613  *	USB_*		- refer to usbai.h
1614  *
1615  * Note:
1616  *	If the caller specified  USB_FLAGS_NOSLEEP, it must be
1617  *	capable of reliably recovering from a failure return
1618  */
1619 int
1620 usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
1621 		void	(*func)(void *),
1622 		void	*arg,
1623 		usb_flags_t flag)
1624 {
1625 	int	tq_flag;
1626 	taskq_t *taskq;
1627 
1628 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1629 	    "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
1630 	    ph_data, func, arg, flag);
1631 
1632 	if (func == NULL) {
1633 
1634 		return (USB_INVALID_ARGS);
1635 	}
1636 
1637 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1638 
1639 	if (ph_data && ph_data->p_taskq) {
1640 		taskq = ph_data->p_taskq;
1641 	} else {
1642 		taskq = system_taskq;
1643 		tq_flag |= TQ_NOQUEUE;
1644 	}
1645 
1646 	if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) {
1647 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1648 		    "usba_async_ph_req: failure");
1649 
1650 		return (USB_FAILURE);
1651 	}
1652 
1653 	return (USB_SUCCESS);
1654 }
1655 
1656 
1657 /*
1658  * utility functions to display CR, CB, return values
1659  */
1660 typedef struct conv_table {
1661 	int		what;
1662 	const char	*name;
1663 } conv_table_t;
1664 
1665 static const char *
1666 usba_get_name(conv_table_t *conv_table, int value)
1667 {
1668 	int i;
1669 	for (i = 0; conv_table[i].name != NULL; i++) {
1670 		if (conv_table[i].what == value) {
1671 
1672 			return (conv_table[i].name);
1673 		}
1674 	}
1675 
1676 	return ("unknown");
1677 }
1678 
1679 
1680 static conv_table_t cr_table[] = {
1681 	{ USB_CR_OK,		"<no errors detected>" },
1682 	{ USB_CR_CRC,		"<crc error detected>" },
1683 	{ USB_CR_BITSTUFFING,	"<Bit stuffing violation>" },
1684 	{ USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
1685 	{ USB_CR_STALL, 	"<Endpoint returned stall PID>" },
1686 	{ USB_CR_DEV_NOT_RESP,	"<Device not responding>" },
1687 	{ USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
1688 	{ USB_CR_UNEXP_PID,	"<Receive PID was not valid>" },
1689 	{ USB_CR_DATA_OVERRUN,	"<Data size exceeded>" },
1690 	{ USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
1691 	{ USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
1692 	{ USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
1693 	{ USB_CR_TIMEOUT,	"<Command timed out>" },
1694 	{ USB_CR_NOT_ACCESSED,	"<Not accessed by hardware>" },
1695 	{ USB_CR_NO_RESOURCES,	"<No resources>" },
1696 	{ USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
1697 	{ USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
1698 	{ USB_CR_PIPE_CLOSING,	"<Intr/ISOC IN pipe being closed>" },
1699 	{ USB_CR_PIPE_RESET,	"<Intr/ISOC IN pipe reset>" },
1700 	{ USB_CR_NOT_SUPPORTED, "<Command not supported>" },
1701 	{ USB_CR_FLUSHED,	"<Req was flushed>" },
1702 	{ USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
1703 	{ 0,			NULL }
1704 };
1705 
1706 const char *
1707 usb_str_cr(usb_cr_t cr)
1708 {
1709 	return (usba_get_name(cr_table, cr));
1710 }
1711 
1712 
1713 static conv_table_t cb_flags_table[] = {
1714 	{ USB_CB_NO_INFO,	"<callback processed>" },
1715 	{ USB_CB_STALL_CLEARED, "<stall cleared>" },
1716 	{ USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
1717 	{ USB_CB_PROTOCOL_STALL, "<protocol stall>" },
1718 	{ USB_CB_RESET_PIPE,	"<pipe reset>" },
1719 	{ USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
1720 	{ USB_CB_NO_RESOURCES,	"<no resources>" },
1721 	{ USB_CB_SUBMIT_FAILED, "<submit failed>" },
1722 	{ USB_CB_INTR_CONTEXT,	"<Callback executing in interrupt context>" },
1723 	{ 0,			NULL }
1724 };
1725 
1726 /*ARGSUSED*/
1727 char *
1728 usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
1729 {
1730 	int i;
1731 	buffer[0] = '\0';
1732 	if (cb_flags == USB_CB_NO_INFO) {
1733 		(void) strncpy(buffer, cb_flags_table[0].name, length);
1734 	} else {
1735 		for (i = 0; cb_flags_table[i].name != NULL; i++) {
1736 			if (cb_flags & cb_flags_table[i].what) {
1737 				(void) strncpy(&buffer[strlen(buffer)],
1738 				    cb_flags_table[0].name,
1739 				    length - strlen(buffer) - 1);
1740 			}
1741 		}
1742 	}
1743 
1744 	return (buffer);
1745 }
1746 
1747 
1748 static conv_table_t pipe_state_table[] = {
1749 	{ USB_PIPE_STATE_CLOSED,	"<closed>" },
1750 	{ USB_PIPE_STATE_IDLE,		"<idle>" },
1751 	{ USB_PIPE_STATE_ACTIVE,	"<active>" },
1752 	{ USB_PIPE_STATE_ERROR,		"<error>" },
1753 	{ USB_PIPE_STATE_CLOSING,	"<closing>" },
1754 	{ 0,				NULL }
1755 };
1756 
1757 const char *
1758 usb_str_pipe_state(usb_pipe_state_t state)
1759 {
1760 	return (usba_get_name(pipe_state_table, state));
1761 }
1762 
1763 
1764 static conv_table_t dev_state[] = {
1765 	{ USB_DEV_ONLINE,	"<online>" },
1766 	{ USB_DEV_DISCONNECTED,	"<disconnected>" },
1767 	{ USB_DEV_SUSPENDED,	"<suspended>" },
1768 	{ USB_DEV_PWRED_DOWN,	"<powered down>" },
1769 	{ 0,			NULL }
1770 };
1771 
1772 const char *
1773 usb_str_dev_state(int state)
1774 {
1775 	return (usba_get_name(dev_state, state));
1776 }
1777 
1778 
1779 static conv_table_t rval_table[] = {
1780 	{ USB_SUCCESS,		"<success>" },
1781 	{ USB_FAILURE,		"<failure>" },
1782 	{ USB_NO_RESOURCES,	"<no resources>" },
1783 	{ USB_NO_BANDWIDTH,	"<no bandwidth>" },
1784 	{ USB_NOT_SUPPORTED,	"<not supported>" },
1785 	{ USB_PIPE_ERROR,	"<pipe error>" },
1786 	{ USB_INVALID_PIPE,	"<invalid pipe>" },
1787 	{ USB_NO_FRAME_NUMBER,	"<no frame number>" },
1788 	{ USB_INVALID_START_FRAME, "<invalid frame>" },
1789 	{ USB_HC_HARDWARE_ERROR, "<hw error>" },
1790 	{ USB_INVALID_REQUEST,	"<invalid request>" },
1791 	{ USB_INVALID_CONTEXT,	"<invalid context>" },
1792 	{ USB_INVALID_VERSION,	"<invalid version>" },
1793 	{ USB_INVALID_ARGS,	"<invalid args>" },
1794 	{ USB_INVALID_PERM,	"<invalid perms>" },
1795 	{ USB_BUSY,		"<busy>" },
1796 	{ 0,			NULL }
1797 };
1798 
1799 const char *
1800 usb_str_rval(int rval)
1801 {
1802 	return (usba_get_name(rval_table, rval));
1803 }
1804 
1805 
1806 /*
1807  * function to convert USB return values to close errno
1808  */
1809 static struct usb_rval2errno_entry {
1810 	int	rval;
1811 	int	Errno;
1812 } usb_rval2errno_table[] = {
1813 	{ USB_SUCCESS,			0	},
1814 	{ USB_FAILURE,			EIO	},
1815 	{ USB_NO_RESOURCES,		ENOMEM	},
1816 	{ USB_NO_BANDWIDTH,		EAGAIN	},
1817 	{ USB_NOT_SUPPORTED,		ENOTSUP },
1818 	{ USB_PIPE_ERROR,		EIO	},
1819 	{ USB_INVALID_PIPE,		EINVAL	},
1820 	{ USB_NO_FRAME_NUMBER,		EINVAL	},
1821 	{ USB_INVALID_START_FRAME,	EINVAL	},
1822 	{ USB_HC_HARDWARE_ERROR,	EIO	},
1823 	{ USB_INVALID_REQUEST,		EINVAL	},
1824 	{ USB_INVALID_CONTEXT,		EINVAL	},
1825 	{ USB_INVALID_VERSION,		EINVAL	},
1826 	{ USB_INVALID_ARGS,		EINVAL	},
1827 	{ USB_INVALID_PERM,		EACCES	},
1828 	{ USB_BUSY,			EBUSY	},
1829 };
1830 
1831 #define	USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
1832 			sizeof (struct usb_rval2errno_entry))
1833 int
1834 usb_rval2errno(int rval)
1835 {
1836 	int i;
1837 
1838 	for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
1839 		if (usb_rval2errno_table[i].rval == rval) {
1840 
1841 			return (usb_rval2errno_table[i].Errno);
1842 		}
1843 	}
1844 
1845 	return (EIO);
1846 }
1847 
1848 
1849 /*
1850  * serialization
1851  */
1852 usb_serialization_t
1853 usb_init_serialization(
1854 	dev_info_t	*dip,
1855 	uint_t		flag)
1856 {
1857 	usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
1858 				sizeof (usba_serialization_impl_t), KM_SLEEP);
1859 	usba_device_t	*usba_device;
1860 	ddi_iblock_cookie_t cookie = NULL;
1861 
1862 	if (dip) {
1863 		usba_device = usba_get_usba_device(dip);
1864 		cookie = usba_hcdi_get_hcdi(
1865 		    usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
1866 	}
1867 	impl_tokenp->s_dip = dip;
1868 	impl_tokenp->s_flag = flag;
1869 	mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
1870 	cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
1871 
1872 	return ((usb_serialization_t)impl_tokenp);
1873 }
1874 
1875 
1876 void
1877 usb_fini_serialization(
1878 	usb_serialization_t tokenp)
1879 {
1880 	usba_serialization_impl_t *impl_tokenp;
1881 
1882 	if (tokenp) {
1883 		impl_tokenp = (usba_serialization_impl_t *)tokenp;
1884 		ASSERT(impl_tokenp->s_count == 0);
1885 		cv_destroy(&impl_tokenp->s_cv);
1886 		mutex_destroy(&impl_tokenp->s_mutex);
1887 		kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
1888 	}
1889 }
1890 
1891 
1892 /*
1893  * usb_serialize_access() permits single threaded access.
1894  *
1895  * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
1896  * it is reentrant with respect to thread. The thread must
1897  * hold and release the same number of times.
1898  *
1899  * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
1900  * it is not reentrant by the same thread. It is something like
1901  * a semaphore.
1902  */
1903 int
1904 usb_serialize_access(
1905 	usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
1906 {
1907 	int			rval = 1;	/* Must be initialized > 0 */
1908 	clock_t			abs_timeout;
1909 	usba_serialization_impl_t *impl_tokenp;
1910 
1911 	impl_tokenp = (usba_serialization_impl_t *)tokenp;
1912 
1913 	/*
1914 	 * Convert delta timeout in ms to absolute timeout in ticks, if used.
1915 	 */
1916 	if ((how_to_wait == USB_TIMEDWAIT) ||
1917 	    (how_to_wait == USB_TIMEDWAIT_SIG)) {
1918 		/* Convert timeout arg (in ms) to hz */
1919 		abs_timeout = ddi_get_lbolt() +
1920 		    drv_usectohz(delta_timeout * 1000);
1921 	}
1922 
1923 	/* Get mutex after calc abs time, to count time waiting for mutex. */
1924 	mutex_enter(&impl_tokenp->s_mutex);
1925 
1926 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1927 	    "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
1928 	    "flg=0x%x, abs_tmo=0x%lx",
1929 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count,
1930 	    impl_tokenp->s_thread, how_to_wait, abs_timeout);
1931 
1932 	if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
1933 	    impl_tokenp->s_thread != curthread) {
1934 
1935 		/*
1936 		 * There are three ways to break out of the loop:
1937 		 * 1) Condition met (s_count == 0) - higher prio test
1938 		 * 2) kill(2) signal received (rval == 0)
1939 		 * 3) timeout occurred (rval == -1)
1940 		 * If condition met, whether or not signal or timeout occurred
1941 		 * take access.  If condition not met, check other exit means.
1942 		 */
1943 		while (impl_tokenp->s_count != 0) {
1944 
1945 			/* cv_timedwait* returns -1 on timeout. */
1946 			/* cv_wait*_sig returns 0 on (kill(2)) signal. */
1947 			if (rval <= 0) {
1948 				mutex_exit(&impl_tokenp->s_mutex);
1949 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
1950 				    usbai_log_handle,
1951 				    "usb_serialize_access: "
1952 				    "tok=0x%p exit due to %s", impl_tokenp,
1953 				    ((rval == 0) ? "signal" : "timeout"));
1954 
1955 				return (rval);
1956 			}
1957 
1958 			switch (how_to_wait) {
1959 			default:
1960 				how_to_wait = USB_WAIT;
1961 				/* FALLTHROUGH */
1962 			case USB_WAIT:
1963 				cv_wait(&impl_tokenp->s_cv,
1964 					&impl_tokenp->s_mutex);
1965 				break;
1966 			case USB_WAIT_SIG:
1967 				rval = cv_wait_sig(&impl_tokenp->s_cv,
1968 						&impl_tokenp->s_mutex);
1969 				break;
1970 			case USB_TIMEDWAIT:
1971 				rval = cv_timedwait(&impl_tokenp->s_cv,
1972 					&impl_tokenp->s_mutex, abs_timeout);
1973 				break;
1974 			case USB_TIMEDWAIT_SIG:
1975 				rval = cv_timedwait_sig(&impl_tokenp->s_cv,
1976 					&impl_tokenp->s_mutex, abs_timeout);
1977 				break;
1978 			}
1979 		}
1980 
1981 		impl_tokenp->s_thread = curthread;
1982 	}
1983 	impl_tokenp->s_count++;
1984 
1985 	ASSERT(!(impl_tokenp->s_count > 1 &&
1986 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
1987 
1988 	mutex_exit(&impl_tokenp->s_mutex);
1989 
1990 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1991 	    "usb_serialize_access exit: tok=0x%p thr=0x%p", impl_tokenp,
1992 	    curthread);
1993 
1994 	return (1);
1995 }
1996 
1997 
1998 /*ARGSUSED*/
1999 int
2000 usb_try_serialize_access(
2001 	usb_serialization_t tokenp, uint_t flag)
2002 {
2003 	usba_serialization_impl_t *impl_tokenp =
2004 					(usba_serialization_impl_t *)tokenp;
2005 	mutex_enter(&impl_tokenp->s_mutex);
2006 
2007 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2008 	    "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2009 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, curthread);
2010 
2011 	/*
2012 	 * If lock is not taken (s_count is 0), take it.
2013 	 * If lock is already taken, the thread is owner and lock
2014 	 * is reentrant, take it.
2015 	 * Otherwise, fail the access.
2016 	 */
2017 	if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
2018 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
2019 		impl_tokenp->s_thread = curthread;
2020 		impl_tokenp->s_count++;
2021 
2022 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2023 		    "usb_try_serialize_access success: tok=0x%p", impl_tokenp);
2024 		mutex_exit(&impl_tokenp->s_mutex);
2025 
2026 		return (USB_SUCCESS);
2027 	}
2028 
2029 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2030 	    "usb_try_serialize_access failed: "
2031 	    "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2032 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count,
2033 	    impl_tokenp->s_thread);
2034 
2035 	mutex_exit(&impl_tokenp->s_mutex);
2036 
2037 	return (USB_FAILURE);
2038 }
2039 
2040 
2041 void
2042 usb_release_access(
2043 	usb_serialization_t tokenp)
2044 {
2045 	usba_serialization_impl_t *impl_tokenp =
2046 					(usba_serialization_impl_t *)tokenp;
2047 	mutex_enter(&impl_tokenp->s_mutex);
2048 
2049 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2050 	    "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
2051 	    impl_tokenp, impl_tokenp->s_dip, impl_tokenp->s_count, curthread);
2052 
2053 	ASSERT(impl_tokenp->s_count > 0);
2054 
2055 	if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
2056 		if (impl_tokenp->s_thread != curthread) {
2057 			USB_DPRINTF_L1(DPRINT_MASK_USBA, usbai_log_handle,
2058 			    "usb_release_access: release from wrong thread");
2059 		}
2060 		ASSERT(impl_tokenp->s_thread == curthread);
2061 	}
2062 
2063 	if (--impl_tokenp->s_count == 0) {
2064 		impl_tokenp->s_thread = NULL;
2065 		cv_broadcast(&impl_tokenp->s_cv);
2066 	}
2067 	mutex_exit(&impl_tokenp->s_mutex);
2068 }
2069 
2070 
2071 /*
2072  * usb_fail_checkpoint:
2073  *	fail checkpoint as driver/device could not be quiesced
2074  */
2075 /*ARGSUSED*/
2076 void
2077 usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
2078 {
2079 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2080 
2081 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2082 	    "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
2083 	    ddi_get_instance(dip));
2084 
2085 	mutex_enter(&usba_device->usb_mutex);
2086 	usba_device->usb_no_cpr++;
2087 	mutex_exit(&usba_device->usb_mutex);
2088 }
2089 
2090 
2091 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
2092 _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
2093 /*
2094  * usba_mk_mctl:
2095  *	create a USB style M_CTL message, given an iocblk and a buffer
2096  *	returns mblk_t * on success, NULL on failure
2097  */
2098 mblk_t *
2099 usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
2100 {
2101 	mblk_t *bp1, *bp2;
2102 
2103 	if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
2104 		*((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
2105 		bp1->b_datap->db_type = M_CTL;
2106 		bp1->b_wptr += sizeof (struct iocblk);
2107 		if (buf != NULL) {
2108 			if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
2109 				bp1->b_cont = bp2;
2110 				bcopy(buf, bp2->b_datap->db_base, len);
2111 				bp2->b_wptr += len;
2112 			} else {
2113 				freemsg(bp1);
2114 				bp1 = NULL;
2115 			}
2116 		}
2117 	}
2118 
2119 	return (bp1);
2120 }
2121 
2122 
2123 #ifdef ALLOCB_TEST
2124 #undef	allocb
2125 mblk_t *
2126 usba_test_allocb(size_t size, uint_t pri)
2127 {
2128 	if (ddi_get_lbolt() & 0x1) {
2129 
2130 		return (NULL);
2131 	} else {
2132 
2133 		return (allocb(size, pri));
2134 	}
2135 }
2136 #endif
2137