xref: /illumos-gate/usr/src/uts/common/io/usb/usba/usbai_util.c (revision 0e233487902b546a8949e2147ff8af45b1afc77c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * USBA: Solaris USB Architecture support
29  *
30  * Utility functions
31  */
32 #define	USBA_FRAMEWORK
33 #include <sys/usb/usba/usba_impl.h>
34 #include <sys/usb/usba/hcdi_impl.h>
35 
36 extern void usba_free_evdata(usba_evdata_t *);
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", (void *)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 				    (void *)&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", (void *)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 /* check whether the interface is in this interface association */
819 boolean_t
820 usba_check_if_in_ia(dev_info_t *dip, int n_if)
821 {
822 	int first_if, if_count;
823 
824 	first_if = usb_get_if_number(dip);
825 	if_count = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
826 	    DDI_PROP_DONTPASS, "interface-count", -1);
827 	if_count += first_if;
828 
829 	return ((n_if >= first_if && n_if < if_count) ? B_TRUE : B_FALSE);
830 }
831 
832 
833 uint8_t
834 usba_get_ifno(dev_info_t *dip)
835 {
836 	int interface_num = usb_get_if_number(dip);
837 
838 	return (interface_num < 0 ? 0 : interface_num);
839 }
840 
841 
842 /*
843  * usb_set_alt_if:
844  *	set the alternate interface number. Issues USB_REQ_SET_IF
845  *	This function will access the device
846  *
847  * Arguments:
848  *	dip		- pointer to devinfo of the client
849  *	if_number	- interface number
850  *	alt_number	- alternate interface number
851  *	flags		- USB_FLAGS_SLEEP:
852  *				wait for completion
853  *	cb		- if USB_FLAGS_SLEEP has not been specified
854  *			  this callback function will be called on
855  *			  completion. This callback may be NULL
856  *			  and no notification of completion will then
857  *			  be provided.
858  *	cb_arg		- 2nd argument to callback function.
859  *
860  *
861  * return values:
862  *	USB_SUCCESS	- alternate was set
863  *	USB_FAILURE	- alternate could not be set because pipes
864  *			  were still open or some access error occurred
865  *	USB_*		- refer to usbai.h
866  *
867  * Note:
868  *	we can't easily check if all pipes to endpoints for this interface
869  *	are closed since we don't have a map of which endpoints belong
870  *	to which interface. If we had this map, we would need to update
871  *	this on each alternative or configuration switch
872  */
873 int
874 usb_set_alt_if(dev_info_t	*dip,
875 		uint_t		interface,
876 		uint_t		alt_number,
877 		usb_flags_t	usb_flags,
878 		void		(*cb)(
879 					usb_pipe_handle_t ph,
880 					usb_opaque_t	arg,
881 					int		rval,
882 					usb_cb_flags_t	flags),
883 		usb_opaque_t	cb_arg)
884 {
885 	usb_pipe_handle_t	ph;
886 
887 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
888 	    "usb_set_alt_if: %s%d, if = %d alt = %d, uf = 0x%x",
889 	    ddi_driver_name(dip), ddi_get_instance(dip),
890 	    interface, alt_number, usb_flags);
891 
892 	if (dip == NULL) {
893 
894 		return (USB_INVALID_ARGS);
895 	}
896 
897 	if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
898 
899 		return (USB_INVALID_CONTEXT);
900 	}
901 
902 	ph = usba_get_dflt_pipe_handle(dip);
903 	if (usba_hold_ph_data(ph) == NULL) {
904 
905 		return (USB_INVALID_PIPE);
906 	}
907 
908 	return (usba_pipe_setup_func_call(dip,
909 	    usba_sync_set_alt_if, (usba_ph_impl_t *)ph,
910 	    (usb_opaque_t)((uintptr_t)((interface << 8) | alt_number)),
911 	    usb_flags, cb, cb_arg));
912 }
913 
914 
915 static int
916 usba_sync_set_alt_if(dev_info_t	*dip,
917 		usba_ph_impl_t	*ph_impl,
918 		usba_pipe_async_req_t	*request,
919 		usb_flags_t	flags)
920 {
921 	int		rval;
922 	usb_cr_t	completion_reason;
923 	usb_cb_flags_t	cb_flags;
924 	usb_opaque_t	arg = request->arg;
925 	int		interface = ((uintptr_t)arg >> 8) & 0xff;
926 	int		alt_number = (uintptr_t)arg & 0xff;
927 	usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
928 	    (usb_pipe_handle_t)ph_impl);
929 
930 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
931 	    "usb_set_alt_if: %s, interface#=0x%x, alt#=0x%x, "
932 	    "uf=0x%x", ddi_node_name(dip), interface,
933 	    alt_number, flags);
934 
935 	/* if we don't own the device, we must own the interface or ia */
936 	if (!usb_owns_device(dip) && !usba_check_if_in_ia(dip, interface) &&
937 	    (interface != usb_get_if_number(dip))) {
938 		usba_release_ph_data(ph_data->p_ph_impl);
939 
940 		return (USB_INVALID_PERM);
941 	}
942 
943 	/* set the alternate setting */
944 	rval = usb_pipe_sync_ctrl_xfer(dip, usba_get_dflt_pipe_handle(dip),
945 	    USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_IF,
946 	    USB_REQ_SET_IF,
947 	    alt_number,
948 	    interface,
949 	    0,
950 	    NULL, 0,
951 	    &completion_reason,
952 	    &cb_flags, flags | USB_FLAGS_SLEEP);
953 
954 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
955 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
956 
957 	usba_release_ph_data(ph_data->p_ph_impl);
958 
959 	return (rval);
960 }
961 
962 
963 /*
964  * usb_get_alt_if:
965  *	get the alternate interface number. Issues USB_REQ_GET_IF
966  *	This function will access the device and block
967  *
968  * Arguments:
969  *	dip			- pointer to devinfo of the client
970  *	if_number	- interface number
971  *	alt_number	- alternate interface number
972  *	flags			- none but USB_FLAGS_SLEEP may be passed
973  *
974  * return values:
975  *	USB_SUCCESS:		alternate was set
976  *	USB_FAILURE:		alternate could not be set because pipes
977  *				were still open or some access error occurred
978  */
979 int
980 usb_get_alt_if(dev_info_t	*dip,
981 		uint_t		if_number,
982 		uint_t		*alt_number,
983 		usb_flags_t	flags)
984 {
985 	int		rval;
986 	usb_cr_t	completion_reason;
987 	mblk_t		*data = NULL;
988 	usb_cb_flags_t	cb_flags;
989 	usb_pipe_handle_t ph;
990 
991 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
992 	    "usb_get_alt_if: %s, interface# = 0x%x, altp = 0x%p, "
993 	    "uf = 0x%x", ddi_node_name(dip), if_number,
994 	    (void *)alt_number, flags);
995 
996 	if ((alt_number == NULL) || (dip == NULL)) {
997 
998 		return (USB_INVALID_ARGS);
999 	}
1000 
1001 	ph = usba_get_dflt_pipe_handle(dip);
1002 
1003 	/*
1004 	 * get the alternate setting
1005 	 */
1006 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1007 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_RCPT_IF,
1008 	    USB_REQ_GET_IF,
1009 	    0,
1010 	    if_number,
1011 	    1,		/* returns one byte of data */
1012 	    &data, 0,
1013 	    &completion_reason,
1014 	    &cb_flags, flags);
1015 
1016 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1017 	    "rval=%d cb_flags=%d cr=%d", rval, cb_flags, completion_reason);
1018 
1019 	if ((rval == USB_SUCCESS) && data &&
1020 	    ((data->b_wptr - data->b_rptr) == 1)) {
1021 		*alt_number = *(data->b_rptr);
1022 	} else {
1023 		*alt_number = 0;
1024 		if (rval == USB_SUCCESS) {
1025 			rval = USB_FAILURE;
1026 		}
1027 	}
1028 
1029 	freemsg(data);
1030 
1031 	return (rval);
1032 }
1033 
1034 
1035 /*
1036  * usba_get_cfg_cloud:
1037  *	Get descriptor cloud for a given configuration.
1038  *
1039  * Arguments:
1040  *	dip			- pointer to devinfo of the client
1041  *	default_ph		- default pipe handle
1042  *	cfg			- which configuration to retrieve raw cloud of
1043  *
1044  * Returns:
1045  *	on success: mblock containing the raw data.  Caller must free.
1046  *	on failure: NULL
1047  */
1048 static mblk_t *
1049 usba_get_cfg_cloud(dev_info_t *dip, usb_pipe_handle_t default_ph, int cfg)
1050 {
1051 	usb_cr_t	completion_reason;
1052 	usb_cb_flags_t	cb_flags;
1053 	usb_cfg_descr_t cfg_descr;
1054 	mblk_t		*pdata = NULL;
1055 
1056 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1057 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1058 	    USB_REQ_GET_DESCR,
1059 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1060 	    0,
1061 	    USB_CFG_DESCR_SIZE,
1062 	    &pdata,
1063 	    0,
1064 	    &completion_reason,
1065 	    &cb_flags,
1066 	    0) != USB_SUCCESS) {
1067 
1068 		freemsg(pdata);
1069 
1070 		return (NULL);
1071 	}
1072 
1073 	(void) usb_parse_cfg_descr(pdata->b_rptr,
1074 	    pdata->b_wptr - pdata->b_rptr, &cfg_descr, USB_CFG_DESCR_SIZE);
1075 	freemsg(pdata);
1076 	pdata = NULL;
1077 
1078 	if (usb_pipe_sync_ctrl_xfer(dip, default_ph,
1079 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
1080 	    USB_REQ_GET_DESCR,
1081 	    USB_DESCR_TYPE_SETUP_CFG | cfg,
1082 	    0,
1083 	    cfg_descr.wTotalLength,
1084 	    &pdata,
1085 	    0,
1086 	    &completion_reason,
1087 	    &cb_flags,
1088 	    0) != USB_SUCCESS) {
1089 
1090 		freemsg(pdata);
1091 
1092 		return (NULL);
1093 	}
1094 
1095 	return (pdata);
1096 }
1097 
1098 /*
1099  * usb_check_same_device:
1100  *	Check if the device connected to the port is the same as
1101  *	the previous device that was in the port.  The previous device is
1102  *	represented by the dip on record for the port.	Print a message
1103  *	if the device is different.  If device_string arg is not NULL, it is
1104  *	included in the message.  Can block.
1105  *
1106  * Arguments:
1107  *	dip			- pointer to devinfo of the client
1108  *	log_handle		- handle to which messages are logged
1109  *	log_level		- one of USB_LOG_*
1110  *	log_mask		- logging mask
1111  *	check_mask		- one mask containing things to check:
1112  *					USB_CHK_BASIC: empty mask;
1113  *						these checks are always done.
1114  *					USB_CHK_VIDPID:
1115  *						check vid, pid only.
1116  *					USB_CHK_SERIAL: check match on device
1117  *						serial number.
1118  *					USB_CHK_CFG: check all raw config
1119  *						clouds for a match.
1120  *				NOTE: descr length and content always checked
1121  *	device_string		- Device string to appear in error message
1122  *
1123  * return values:
1124  *	USB_SUCCESS:		same device
1125  *	USB_INVALID_VERSION	not same device
1126  *	USB_FAILURE:		Failure processing request
1127  *	USB_INVALID_ARG:	dip is invalid
1128  */
1129 int
1130 usb_check_same_device(dev_info_t *dip, usb_log_handle_t log_handle,
1131     int log_level, int log_mask, uint_t check_mask, char *device_string)
1132 {
1133 	usb_dev_descr_t		usb_dev_descr;
1134 	usba_device_t		*usba_device;
1135 	mblk_t			*pdata = NULL;
1136 	uint16_t		length;
1137 	int			rval;
1138 	char			*buf;
1139 	usb_cr_t		completion_reason;
1140 	usb_cb_flags_t		cb_flags;
1141 	boolean_t		match = B_TRUE;
1142 	usb_pipe_handle_t	def_ph;
1143 
1144 	if (dip == NULL) {
1145 
1146 		return (USB_INVALID_ARGS);
1147 	}
1148 
1149 	usba_device = usba_get_usba_device(dip);
1150 	length = usba_device->usb_dev_descr->bLength;
1151 	def_ph = usba_get_dflt_pipe_handle(dip);
1152 	ASSERT(def_ph);
1153 
1154 	/* get the "new" device descriptor */
1155 	rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
1156 	    USB_DEV_REQ_DEV_TO_HOST |
1157 	    USB_DEV_REQ_TYPE_STANDARD,
1158 	    USB_REQ_GET_DESCR,		/* bRequest */
1159 	    USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
1160 	    0,				/* wIndex */
1161 	    length,				/* wLength */
1162 	    &pdata, 0,
1163 	    &completion_reason,
1164 	    &cb_flags, USB_FLAGS_SLEEP);
1165 
1166 	if (rval != USB_SUCCESS) {
1167 		if (!((completion_reason == USB_CR_DATA_OVERRUN) && (pdata))) {
1168 			USB_DPRINTF_L3(DPRINT_MASK_USBA, usbai_log_handle,
1169 			    "getting device descriptor failed (%d)", rval);
1170 			freemsg(pdata);
1171 
1172 			return (USB_FAILURE);
1173 		}
1174 	}
1175 
1176 	ASSERT(pdata != NULL);
1177 
1178 	(void) usb_parse_dev_descr(pdata->b_rptr,
1179 	    pdata->b_wptr - pdata->b_rptr, &usb_dev_descr,
1180 	    sizeof (usb_dev_descr_t));
1181 
1182 	freemsg(pdata);
1183 	pdata = NULL;
1184 
1185 	/* Always check the device descriptor length. */
1186 	if (usb_dev_descr.bLength != length) {
1187 		match = B_FALSE;
1188 	}
1189 
1190 	if ((match == B_TRUE) && (check_mask & USB_CHK_VIDPID)) {
1191 		match = (usba_device->usb_dev_descr->idVendor ==
1192 		    usb_dev_descr.idVendor) &&
1193 		    (usba_device->usb_dev_descr->idProduct ==
1194 		    usb_dev_descr.idProduct);
1195 	} else if (bcmp((char *)usba_device->usb_dev_descr,
1196 	    (char *)&usb_dev_descr, length) != 0) {
1197 		match = B_FALSE;
1198 	}
1199 
1200 	/* if requested & this device has a serial number check and compare */
1201 	if ((match == B_TRUE) && ((check_mask & USB_CHK_SERIAL) != 0) &&
1202 	    (usba_device->usb_serialno_str != NULL)) {
1203 		buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1204 		if (usb_get_string_descr(dip, USB_LANG_ID,
1205 		    usb_dev_descr.iSerialNumber, buf,
1206 		    USB_MAXSTRINGLEN) == USB_SUCCESS) {
1207 			match =
1208 			    (strcmp(buf, usba_device->usb_serialno_str) == 0);
1209 		}
1210 		kmem_free(buf, USB_MAXSTRINGLEN);
1211 	}
1212 
1213 	if ((match == B_TRUE) && (check_mask & USB_CHK_CFG)) {
1214 
1215 		uint8_t num_cfgs = usb_dev_descr.bNumConfigurations;
1216 		uint8_t cfg;
1217 		mblk_t *cloud;
1218 
1219 		for (cfg = 0; cfg < num_cfgs; cfg++) {
1220 			cloud = usba_get_cfg_cloud(dip, def_ph, cfg);
1221 			if (cloud == NULL) {
1222 				USB_DPRINTF_L3(DPRINT_MASK_USBA,
1223 				    usbai_log_handle,
1224 				    "Could not retrieve config cloud for "
1225 				    "comparison");
1226 				break;
1227 			}
1228 
1229 			if (bcmp((char *)cloud->b_rptr,
1230 			    usba_device->usb_cfg_array[cfg],
1231 			    cloud->b_wptr - cloud->b_rptr) != 0) {
1232 				freemsg(cloud);
1233 				break;
1234 			}
1235 
1236 			freemsg(cloud);
1237 		}
1238 		if (cfg != num_cfgs) {
1239 			match = B_FALSE;
1240 		}
1241 	}
1242 
1243 	if (match == B_FALSE) {
1244 		boolean_t allocated_here = (device_string == NULL);
1245 		if (allocated_here) {
1246 			device_string =
1247 			    kmem_zalloc(USB_MAXSTRINGLEN, USB_FLAGS_SLEEP);
1248 			(void) usba_get_mfg_prod_sn_str(dip, device_string,
1249 			    USB_MAXSTRINGLEN);
1250 		}
1251 		if (device_string[0] != '\0') {
1252 			(void) usb_log(log_handle, log_level, log_mask,
1253 			    "Cannot access %s.	Please reconnect.",
1254 			    device_string);
1255 		} else {
1256 			(void) usb_log(log_handle, log_level, log_mask,
1257 			    "Device is not identical to the "
1258 			    "previous one this port.\n"
1259 			    "Please disconnect and reconnect");
1260 		}
1261 		if (allocated_here) {
1262 			kmem_free(device_string, USB_MAXSTRINGLEN);
1263 		}
1264 
1265 		return (USB_INVALID_VERSION);
1266 	}
1267 
1268 	return (USB_SUCCESS);
1269 }
1270 
1271 
1272 /*
1273  * usb_pipe_get_state:
1274  *	Return the state of the pipe
1275  *
1276  * Arguments:
1277  *	pipe_handle	- pipe_handle pointer
1278  *	pipe_state	- pointer to copy pipe state to
1279  *	flags:
1280  *		not used other than to check context
1281  *
1282  * Return Values:
1283  *	USB_SUCCESS	- port state returned
1284  *	USB_*		- refer to usbai.h
1285  */
1286 int
1287 usb_pipe_get_state(usb_pipe_handle_t	pipe_handle,
1288 	    usb_pipe_state_t	*pipe_state,
1289 	    usb_flags_t		usb_flags)
1290 {
1291 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1292 
1293 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1294 	    "usb_pipe_get_state: ph_data=0x%p uf=0x%x", (void *)ph_data,
1295 	    usb_flags);
1296 
1297 	if (pipe_state == NULL) {
1298 		if (ph_data) {
1299 			usba_release_ph_data(ph_data->p_ph_impl);
1300 		}
1301 
1302 		return (USB_INVALID_ARGS);
1303 	}
1304 
1305 	if (ph_data == NULL) {
1306 		*pipe_state = USB_PIPE_STATE_CLOSED;
1307 
1308 		return (USB_SUCCESS);
1309 	}
1310 
1311 	mutex_enter(&ph_data->p_mutex);
1312 	*pipe_state = usba_get_ph_state(ph_data);
1313 	mutex_exit(&ph_data->p_mutex);
1314 
1315 	usba_release_ph_data(ph_data->p_ph_impl);
1316 
1317 	return (USB_SUCCESS);
1318 }
1319 
1320 
1321 /*
1322  * usba_pipe_get_policy:
1323  *	Return a pipe's policy
1324  *
1325  * Arguments:
1326  *	pipe_handle	- pipe_handle pointer
1327  *
1328  * Return Values:
1329  *	On success: the pipe's policy
1330  *	On failure: NULL
1331  */
1332 usb_pipe_policy_t
1333 *usba_pipe_get_policy(usb_pipe_handle_t pipe_handle)
1334 {
1335 	usb_pipe_policy_t *pp = NULL;
1336 
1337 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1338 
1339 	if (ph_data) {
1340 		pp = &ph_data->p_policy;
1341 
1342 		usba_release_ph_data(ph_data->p_ph_impl);
1343 	}
1344 
1345 	return (pp);
1346 }
1347 
1348 
1349 /*
1350  * usb_ep_num:
1351  *	Return the endpoint number for a given pipe handle
1352  *
1353  * Arguments:
1354  *	pipe_handle	- pipe_handle pointer
1355  *
1356  * Return Values:
1357  *	endpoint number
1358  */
1359 int
1360 usb_ep_num(usb_pipe_handle_t pipe_handle)
1361 {
1362 	usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1363 	int ep_num;
1364 
1365 	if (ph_data == NULL) {
1366 
1367 		return (USB_INVALID_PIPE);
1368 	}
1369 
1370 	mutex_enter(&ph_data->p_mutex);
1371 	ep_num = ph_data->p_ep.bEndpointAddress & USB_EP_NUM_MASK;
1372 	mutex_exit(&ph_data->p_mutex);
1373 
1374 	usba_release_ph_data(ph_data->p_ph_impl);
1375 
1376 	return (ep_num);
1377 }
1378 
1379 
1380 /*
1381  * usb_get_status
1382  *	Issues USB_REQ_GET_STATUS to device/endpoint/interface
1383  *	and report in "status" arg.
1384  *
1385  *	status reported for a "device" is
1386  *		RemoteWakeup enabled
1387  *		SelfPowered device?
1388  *
1389  *	status reported for an "interface" is NONE.
1390  *	status reported for an "endpoint" is
1391  *		HALT set (device STALLED?)
1392  *
1393  * Arguments:
1394  *	dip	- pointer to devinfo of the client
1395  *	ph	- pipe handle
1396  *	type	- bmRequestType to be used
1397  *	what	- 0 for device, otherwise interface or ep number
1398  *	status	- user supplied pointer for storing the status
1399  *	flags	- USB_FLAGS_SLEEP (mandatory)
1400  *
1401  * Return Values:
1402  *	valid usb_status_t	or USB_FAILURE
1403  */
1404 int
1405 usb_get_status(dev_info_t		*dip,
1406 		usb_pipe_handle_t	ph,
1407 		uint_t			type,	/* bmRequestType */
1408 		uint_t			what,	/* 0, interface, ept number */
1409 		uint16_t		*status,
1410 		usb_flags_t		flags)
1411 {
1412 	int		rval;
1413 	usb_cr_t	completion_reason;
1414 	mblk_t		*data = NULL;
1415 	usb_cb_flags_t	cb_flags;
1416 
1417 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1418 	    "usb_get_status: type = 0x%x, what = 0x%x, uf = 0x%x",
1419 	    type, what, flags);
1420 
1421 	if ((status == NULL) || (dip == NULL)) {
1422 
1423 		return (USB_INVALID_ARGS);
1424 	}
1425 	if (ph == NULL) {
1426 
1427 		return (USB_INVALID_PIPE);
1428 	}
1429 
1430 	type |= USB_DEV_REQ_DEV_TO_HOST;
1431 
1432 	/* get the status */
1433 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1434 	    type,
1435 	    USB_REQ_GET_STATUS,
1436 	    0,
1437 	    what,
1438 	    USB_GET_STATUS_LEN,	/* status is fixed 2 bytes long */
1439 	    &data, 0,
1440 	    &completion_reason, &cb_flags, flags);
1441 
1442 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1443 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1444 
1445 	if ((rval == USB_SUCCESS) && data &&
1446 	    ((data->b_wptr - data->b_rptr) == USB_GET_STATUS_LEN)) {
1447 		*status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
1448 	} else {
1449 		*status = 0;
1450 		if (rval == USB_SUCCESS) {
1451 			rval = USB_FAILURE;
1452 		}
1453 	}
1454 
1455 	freemsg(data);
1456 
1457 	return (rval);
1458 }
1459 
1460 
1461 /*
1462  * usb_clear_feature:
1463  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1464  *
1465  * Arguments:
1466  *	dip		- pointer to devinfo of the client
1467  *	ph		- pipe handle pointer
1468  *	type		- bmRequestType to be used
1469  *	feature		- feature to be cleared
1470  *	what		- 0 for device, otherwise interface or ep number
1471  *	flags		- none (but will sleep)
1472  *
1473  * Return Values:
1474  *	USB_SUCCESS	- on doing a successful clear feature
1475  *	USB_FAILURE	- on failure
1476  *	USB_*		- refer to usbai.h
1477  */
1478 int
1479 usb_clear_feature(dev_info_t		*dip,
1480 		usb_pipe_handle_t	ph,
1481 		uint_t			type,	/* bmRequestType */
1482 		uint_t			feature,
1483 		uint_t			what,	/* 0, interface, ept number */
1484 		usb_flags_t		flags)
1485 {
1486 	int		rval;
1487 	usb_cr_t	completion_reason;
1488 	usb_cb_flags_t	cb_flags;
1489 
1490 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1491 	    "usb_clear_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1492 	    "uf = 0x%x", type, feature, what, flags);
1493 
1494 	if (dip == NULL) {
1495 
1496 		return (USB_INVALID_ARGS);
1497 	}
1498 	if (ph == NULL) {
1499 
1500 		return (USB_INVALID_PIPE);
1501 	}
1502 
1503 	/* issue Clear feature */
1504 	rval = usb_pipe_sync_ctrl_xfer(dip, ph,
1505 	    type,
1506 	    USB_REQ_CLEAR_FEATURE,
1507 	    feature,
1508 	    what,
1509 	    0,
1510 	    NULL, 0,
1511 	    &completion_reason,
1512 	    &cb_flags, flags | USB_FLAGS_SLEEP);
1513 
1514 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1515 	    "rval=%d, cb_flags=%d, cr=%d", rval, cb_flags, completion_reason);
1516 
1517 	return (rval);
1518 }
1519 
1520 
1521 /*
1522  * usb_clr_feature:
1523  *	Issue USB_REQ_CLEAR_FEATURE to endpoint/device/interface
1524  *
1525  * Arguments:
1526  *	dip		- pointer to devinfo of the client
1527  *	type		- bmRequestType to be used
1528  *	feature		- feature to be cleared
1529  *	what		- 0 for device, otherwise interface or ep number
1530  *	flags		- USB_FLAGS_SLEEP:
1531  *				wait for completion
1532  *	cb		- if USB_FLAGS_SLEEP has not been specified
1533  *			  this callback function will be called on
1534  *			  completion. This callback may be NULL
1535  *			  and no notification of completion will then
1536  *			  be provided.
1537  *	cb_arg		- 2nd argument to callback function.
1538  *
1539  *
1540  * Return Values:
1541  *	USB_SUCCESS	- on doing a successful clear feature
1542  *	USB_FAILURE	- on failure
1543  *	USB_*		- refer to usbai.h
1544  */
1545 int
1546 usb_clr_feature(
1547 		dev_info_t	*dip,
1548 		uint_t		type,	/* bmRequestType */
1549 		uint_t		feature,
1550 		uint_t		what,	/* 0, interface, ept number */
1551 		usb_flags_t	flags,
1552 		void		(*cb)(
1553 					usb_pipe_handle_t ph,
1554 					usb_opaque_t	arg,
1555 					int		rval,
1556 					usb_cb_flags_t	flags),
1557 		usb_opaque_t	cb_arg)
1558 {
1559 	usb_pipe_handle_t ph;
1560 
1561 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1562 	    "usb_clr_feature: type = 0x%x, feature = 0x%x, what = 0x%x "
1563 	    "uf = 0x%x", type, feature, what, flags);
1564 
1565 	if (dip == NULL) {
1566 
1567 		return (USB_INVALID_ARGS);
1568 	}
1569 
1570 	if ((flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1571 
1572 		return (USB_INVALID_CONTEXT);
1573 	}
1574 
1575 	ph = usba_get_dflt_pipe_handle(dip);
1576 	if (usba_hold_ph_data(ph) == NULL) {
1577 
1578 		return (USB_INVALID_PIPE);
1579 	}
1580 
1581 	return (usba_pipe_setup_func_call(dip,
1582 	    usba_sync_clear_feature, (usba_ph_impl_t *)ph,
1583 	    (usb_opaque_t)((uintptr_t)((type << 16 | feature << 8 | what))),
1584 	    flags, cb, cb_arg));
1585 }
1586 
1587 
1588 static int
1589 usba_sync_clear_feature(dev_info_t *dip,
1590 	usba_ph_impl_t		*ph_impl,
1591 	usba_pipe_async_req_t	*req,
1592 	usb_flags_t		usb_flags)
1593 {
1594 	uint_t	n = (uint_t)((uintptr_t)(req->arg));
1595 	uint_t	type = ((uint_t)n >> 16) & 0xff;
1596 	uint_t	feature = ((uint_t)n >> 8) & 0xff;
1597 	uint_t	what = (uint_t)n & 0xff;
1598 	int	rval;
1599 
1600 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1601 	    "usb_sync_clear_feature: "
1602 	    "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
1603 	    (void *)dip, (void *)ph_impl, type, feature, what, usb_flags);
1604 
1605 	rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
1606 	    feature, what, usb_flags);
1607 
1608 	usba_release_ph_data(ph_impl);
1609 
1610 	return (rval);
1611 }
1612 
1613 
1614 /*
1615  * usb_async_req:
1616  *	function used to dispatch a request to the taskq
1617  *
1618  * Arguments:
1619  *	dip	- pointer to devinfo node
1620  *	func	- pointer to function issued by taskq
1621  *	flag	- USB_FLAGS_SLEEP mostly
1622  *
1623  * Return Values:
1624  *	USB_SUCCESS	- on doing a successful taskq invocation
1625  *	USB_FAILURE	- on failure
1626  *	USB_*		- refer to usbai.h
1627  */
1628 int
1629 usb_async_req(dev_info_t *dip,
1630 		void	(*func)(void *),
1631 		void	*arg,
1632 		usb_flags_t flag)
1633 {
1634 	int tq_flag;
1635 
1636 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1637 	    "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
1638 	    (void *)dip, (void *)func, arg, flag);
1639 
1640 	if ((dip == NULL) || (func == NULL)) {
1641 
1642 		return (USB_INVALID_ARGS);
1643 	}
1644 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1645 	if (flag & USB_FLAGS_NOQUEUE) {
1646 		tq_flag |= TQ_NOQUEUE;
1647 	}
1648 
1649 	if (!taskq_dispatch(system_taskq, func, (void *)arg,
1650 	    tq_flag)) {
1651 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1652 		    "usb_async_req: failure");
1653 
1654 		return (USB_FAILURE);
1655 	}
1656 
1657 	return (USB_SUCCESS);
1658 }
1659 
1660 /*
1661  * usba_async_ph_req:
1662  *	function used to dispatch a request to the ph taskq
1663  *
1664  * Arguments:
1665  *	ph_data	- pointer to pipe handle data
1666  *	func	- pointer to function issued by taskq
1667  *	flag	- USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
1668  *
1669  * Return Values:
1670  *	USB_SUCCESS	- on doing a successful taskq invocation
1671  *	USB_FAILURE	- on failure
1672  *	USB_*		- refer to usbai.h
1673  *
1674  * Note:
1675  *	If the caller specified  USB_FLAGS_NOSLEEP, it must be
1676  *	capable of reliably recovering from a failure return
1677  */
1678 int
1679 usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
1680 		void	(*func)(void *),
1681 		void	*arg,
1682 		usb_flags_t flag)
1683 {
1684 	int	tq_flag;
1685 	taskq_t *taskq;
1686 
1687 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1688 	    "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
1689 	    (void *)ph_data, (void *)func, arg, flag);
1690 
1691 	if (func == NULL) {
1692 
1693 		return (USB_INVALID_ARGS);
1694 	}
1695 
1696 	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1697 
1698 	if (ph_data && ph_data->p_taskq) {
1699 		taskq = ph_data->p_taskq;
1700 	} else {
1701 		taskq = system_taskq;
1702 		tq_flag |= TQ_NOQUEUE;
1703 	}
1704 
1705 	if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) {
1706 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1707 		    "usba_async_ph_req: failure");
1708 
1709 		return (USB_FAILURE);
1710 	}
1711 
1712 	return (USB_SUCCESS);
1713 }
1714 
1715 
1716 /*
1717  * utility functions to display CR, CB, return values
1718  */
1719 typedef struct conv_table {
1720 	int		what;
1721 	const char	*name;
1722 } conv_table_t;
1723 
1724 static const char *
1725 usba_get_name(conv_table_t *conv_table, int value)
1726 {
1727 	int i;
1728 	for (i = 0; conv_table[i].name != NULL; i++) {
1729 		if (conv_table[i].what == value) {
1730 
1731 			return (conv_table[i].name);
1732 		}
1733 	}
1734 
1735 	return ("unknown");
1736 }
1737 
1738 
1739 static conv_table_t cr_table[] = {
1740 	{ USB_CR_OK,		"<no errors detected>" },
1741 	{ USB_CR_CRC,		"<crc error detected>" },
1742 	{ USB_CR_BITSTUFFING,	"<Bit stuffing violation>" },
1743 	{ USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
1744 	{ USB_CR_STALL, 	"<Endpoint returned stall PID>" },
1745 	{ USB_CR_DEV_NOT_RESP,	"<Device not responding>" },
1746 	{ USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
1747 	{ USB_CR_UNEXP_PID,	"<Receive PID was not valid>" },
1748 	{ USB_CR_DATA_OVERRUN,	"<Data size exceeded>" },
1749 	{ USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
1750 	{ USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
1751 	{ USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
1752 	{ USB_CR_TIMEOUT,	"<Command timed out>" },
1753 	{ USB_CR_NOT_ACCESSED,	"<Not accessed by hardware>" },
1754 	{ USB_CR_NO_RESOURCES,	"<No resources>" },
1755 	{ USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
1756 	{ USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
1757 	{ USB_CR_PIPE_CLOSING,	"<Intr/ISOC IN pipe being closed>" },
1758 	{ USB_CR_PIPE_RESET,	"<Intr/ISOC IN pipe reset>" },
1759 	{ USB_CR_NOT_SUPPORTED, "<Command not supported>" },
1760 	{ USB_CR_FLUSHED,	"<Req was flushed>" },
1761 	{ USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
1762 	{ 0,			NULL }
1763 };
1764 
1765 const char *
1766 usb_str_cr(usb_cr_t cr)
1767 {
1768 	return (usba_get_name(cr_table, cr));
1769 }
1770 
1771 
1772 static conv_table_t cb_flags_table[] = {
1773 	{ USB_CB_NO_INFO,	"<callback processed>" },
1774 	{ USB_CB_STALL_CLEARED, "<stall cleared>" },
1775 	{ USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
1776 	{ USB_CB_PROTOCOL_STALL, "<protocol stall>" },
1777 	{ USB_CB_RESET_PIPE,	"<pipe reset>" },
1778 	{ USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
1779 	{ USB_CB_NO_RESOURCES,	"<no resources>" },
1780 	{ USB_CB_SUBMIT_FAILED, "<submit failed>" },
1781 	{ USB_CB_INTR_CONTEXT,	"<Callback executing in interrupt context>" },
1782 	{ 0,			NULL }
1783 };
1784 
1785 /*ARGSUSED*/
1786 char *
1787 usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
1788 {
1789 	int i;
1790 	buffer[0] = '\0';
1791 	if (cb_flags == USB_CB_NO_INFO) {
1792 		(void) strncpy(buffer, cb_flags_table[0].name, length);
1793 	} else {
1794 		for (i = 0; cb_flags_table[i].name != NULL; i++) {
1795 			if (cb_flags & cb_flags_table[i].what) {
1796 				(void) strncpy(&buffer[strlen(buffer)],
1797 				    cb_flags_table[0].name,
1798 				    length - strlen(buffer) - 1);
1799 			}
1800 		}
1801 	}
1802 
1803 	return (buffer);
1804 }
1805 
1806 
1807 static conv_table_t pipe_state_table[] = {
1808 	{ USB_PIPE_STATE_CLOSED,	"<closed>" },
1809 	{ USB_PIPE_STATE_IDLE,		"<idle>" },
1810 	{ USB_PIPE_STATE_ACTIVE,	"<active>" },
1811 	{ USB_PIPE_STATE_ERROR,		"<error>" },
1812 	{ USB_PIPE_STATE_CLOSING,	"<closing>" },
1813 	{ 0,				NULL }
1814 };
1815 
1816 const char *
1817 usb_str_pipe_state(usb_pipe_state_t state)
1818 {
1819 	return (usba_get_name(pipe_state_table, state));
1820 }
1821 
1822 
1823 static conv_table_t dev_state[] = {
1824 	{ USB_DEV_ONLINE,	"<online>" },
1825 	{ USB_DEV_DISCONNECTED,	"<disconnected>" },
1826 	{ USB_DEV_SUSPENDED,	"<suspended>" },
1827 	{ USB_DEV_PWRED_DOWN,	"<powered down>" },
1828 	{ 0,			NULL }
1829 };
1830 
1831 const char *
1832 usb_str_dev_state(int state)
1833 {
1834 	return (usba_get_name(dev_state, state));
1835 }
1836 
1837 
1838 static conv_table_t rval_table[] = {
1839 	{ USB_SUCCESS,		"<success>" },
1840 	{ USB_FAILURE,		"<failure>" },
1841 	{ USB_NO_RESOURCES,	"<no resources>" },
1842 	{ USB_NO_BANDWIDTH,	"<no bandwidth>" },
1843 	{ USB_NOT_SUPPORTED,	"<not supported>" },
1844 	{ USB_PIPE_ERROR,	"<pipe error>" },
1845 	{ USB_INVALID_PIPE,	"<invalid pipe>" },
1846 	{ USB_NO_FRAME_NUMBER,	"<no frame number>" },
1847 	{ USB_INVALID_START_FRAME, "<invalid frame>" },
1848 	{ USB_HC_HARDWARE_ERROR, "<hw error>" },
1849 	{ USB_INVALID_REQUEST,	"<invalid request>" },
1850 	{ USB_INVALID_CONTEXT,	"<invalid context>" },
1851 	{ USB_INVALID_VERSION,	"<invalid version>" },
1852 	{ USB_INVALID_ARGS,	"<invalid args>" },
1853 	{ USB_INVALID_PERM,	"<invalid perms>" },
1854 	{ USB_BUSY,		"<busy>" },
1855 	{ 0,			NULL }
1856 };
1857 
1858 const char *
1859 usb_str_rval(int rval)
1860 {
1861 	return (usba_get_name(rval_table, rval));
1862 }
1863 
1864 
1865 /*
1866  * function to convert USB return values to close errno
1867  */
1868 static struct usb_rval2errno_entry {
1869 	int	rval;
1870 	int	Errno;
1871 } usb_rval2errno_table[] = {
1872 	{ USB_SUCCESS,			0	},
1873 	{ USB_FAILURE,			EIO	},
1874 	{ USB_NO_RESOURCES,		ENOMEM	},
1875 	{ USB_NO_BANDWIDTH,		EAGAIN	},
1876 	{ USB_NOT_SUPPORTED,		ENOTSUP },
1877 	{ USB_PIPE_ERROR,		EIO	},
1878 	{ USB_INVALID_PIPE,		EINVAL	},
1879 	{ USB_NO_FRAME_NUMBER,		EINVAL	},
1880 	{ USB_INVALID_START_FRAME,	EINVAL	},
1881 	{ USB_HC_HARDWARE_ERROR,	EIO	},
1882 	{ USB_INVALID_REQUEST,		EINVAL	},
1883 	{ USB_INVALID_CONTEXT,		EINVAL	},
1884 	{ USB_INVALID_VERSION,		EINVAL	},
1885 	{ USB_INVALID_ARGS,		EINVAL	},
1886 	{ USB_INVALID_PERM,		EACCES	},
1887 	{ USB_BUSY,			EBUSY	},
1888 };
1889 
1890 #define	USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
1891 			sizeof (struct usb_rval2errno_entry))
1892 int
1893 usb_rval2errno(int rval)
1894 {
1895 	int i;
1896 
1897 	for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
1898 		if (usb_rval2errno_table[i].rval == rval) {
1899 
1900 			return (usb_rval2errno_table[i].Errno);
1901 		}
1902 	}
1903 
1904 	return (EIO);
1905 }
1906 
1907 
1908 /*
1909  * serialization
1910  */
1911 usb_serialization_t
1912 usb_init_serialization(
1913 	dev_info_t	*dip,
1914 	uint_t		flag)
1915 {
1916 	usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
1917 	    sizeof (usba_serialization_impl_t), KM_SLEEP);
1918 	usba_device_t	*usba_device;
1919 	ddi_iblock_cookie_t cookie = NULL;
1920 
1921 	if (dip) {
1922 		usba_device = usba_get_usba_device(dip);
1923 		cookie = usba_hcdi_get_hcdi(
1924 		    usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
1925 	}
1926 	impl_tokenp->s_dip = dip;
1927 	impl_tokenp->s_flag = flag;
1928 	mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
1929 	cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
1930 
1931 	return ((usb_serialization_t)impl_tokenp);
1932 }
1933 
1934 
1935 void
1936 usb_fini_serialization(
1937 	usb_serialization_t tokenp)
1938 {
1939 	usba_serialization_impl_t *impl_tokenp;
1940 
1941 	if (tokenp) {
1942 		impl_tokenp = (usba_serialization_impl_t *)tokenp;
1943 		ASSERT(impl_tokenp->s_count == 0);
1944 		cv_destroy(&impl_tokenp->s_cv);
1945 		mutex_destroy(&impl_tokenp->s_mutex);
1946 		kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
1947 	}
1948 }
1949 
1950 
1951 /*
1952  * usb_serialize_access() permits single threaded access.
1953  *
1954  * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
1955  * it is reentrant with respect to thread. The thread must
1956  * hold and release the same number of times.
1957  *
1958  * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
1959  * it is not reentrant by the same thread. It is something like
1960  * a semaphore.
1961  */
1962 int
1963 usb_serialize_access(
1964 	usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
1965 {
1966 	int			rval = 1;	/* Must be initialized > 0 */
1967 	clock_t			abs_timeout;
1968 	usba_serialization_impl_t *impl_tokenp;
1969 
1970 	impl_tokenp = (usba_serialization_impl_t *)tokenp;
1971 
1972 	/*
1973 	 * Convert delta timeout in ms to absolute timeout in ticks, if used.
1974 	 */
1975 	if ((how_to_wait == USB_TIMEDWAIT) ||
1976 	    (how_to_wait == USB_TIMEDWAIT_SIG)) {
1977 		/* Convert timeout arg (in ms) to hz */
1978 		abs_timeout = ddi_get_lbolt() +
1979 		    drv_usectohz(delta_timeout * 1000);
1980 	}
1981 
1982 	/* Get mutex after calc abs time, to count time waiting for mutex. */
1983 	mutex_enter(&impl_tokenp->s_mutex);
1984 
1985 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1986 	    "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
1987 	    "flg=0x%x, abs_tmo=0x%lx",
1988 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
1989 	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread,
1990 	    how_to_wait, abs_timeout);
1991 
1992 	if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
1993 	    impl_tokenp->s_thread != curthread) {
1994 
1995 		/*
1996 		 * There are three ways to break out of the loop:
1997 		 * 1) Condition met (s_count == 0) - higher prio test
1998 		 * 2) kill(2) signal received (rval == 0)
1999 		 * 3) timeout occurred (rval == -1)
2000 		 * If condition met, whether or not signal or timeout occurred
2001 		 * take access.  If condition not met, check other exit means.
2002 		 */
2003 		while (impl_tokenp->s_count != 0) {
2004 
2005 			/* cv_timedwait* returns -1 on timeout. */
2006 			/* cv_wait*_sig returns 0 on (kill(2)) signal. */
2007 			if (rval <= 0) {
2008 				mutex_exit(&impl_tokenp->s_mutex);
2009 				USB_DPRINTF_L4(DPRINT_MASK_USBA,
2010 				    usbai_log_handle,
2011 				    "usb_serialize_access: "
2012 				    "tok=0x%p exit due to %s",
2013 				    (void *)impl_tokenp,
2014 				    ((rval == 0) ? "signal" : "timeout"));
2015 
2016 				return (rval);
2017 			}
2018 
2019 			switch (how_to_wait) {
2020 			default:
2021 				how_to_wait = USB_WAIT;
2022 				/* FALLTHROUGH */
2023 			case USB_WAIT:
2024 				cv_wait(&impl_tokenp->s_cv,
2025 				    &impl_tokenp->s_mutex);
2026 				break;
2027 			case USB_WAIT_SIG:
2028 				rval = cv_wait_sig(&impl_tokenp->s_cv,
2029 				    &impl_tokenp->s_mutex);
2030 				break;
2031 			case USB_TIMEDWAIT:
2032 				rval = cv_timedwait(&impl_tokenp->s_cv,
2033 				    &impl_tokenp->s_mutex, abs_timeout);
2034 				break;
2035 			case USB_TIMEDWAIT_SIG:
2036 				rval = cv_timedwait_sig(&impl_tokenp->s_cv,
2037 				    &impl_tokenp->s_mutex, abs_timeout);
2038 				break;
2039 			}
2040 		}
2041 
2042 		impl_tokenp->s_thread = curthread;
2043 	}
2044 	impl_tokenp->s_count++;
2045 
2046 	ASSERT(!(impl_tokenp->s_count > 1 &&
2047 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
2048 
2049 	mutex_exit(&impl_tokenp->s_mutex);
2050 
2051 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2052 	    "usb_serialize_access exit: tok=0x%p thr=0x%p", (void *)impl_tokenp,
2053 	    (void *)curthread);
2054 
2055 	return (1);
2056 }
2057 
2058 
2059 /*ARGSUSED*/
2060 int
2061 usb_try_serialize_access(
2062 	usb_serialization_t tokenp, uint_t flag)
2063 {
2064 	usba_serialization_impl_t *impl_tokenp =
2065 	    (usba_serialization_impl_t *)tokenp;
2066 	mutex_enter(&impl_tokenp->s_mutex);
2067 
2068 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2069 	    "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2070 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2071 	    impl_tokenp->s_count, (void *)curthread);
2072 
2073 	/*
2074 	 * If lock is not taken (s_count is 0), take it.
2075 	 * If lock is already taken, the thread is owner and lock
2076 	 * is reentrant, take it.
2077 	 * Otherwise, fail the access.
2078 	 */
2079 	if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
2080 	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
2081 		impl_tokenp->s_thread = curthread;
2082 		impl_tokenp->s_count++;
2083 
2084 		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2085 		    "usb_try_serialize_access success: tok=0x%p",
2086 		    (void *)impl_tokenp);
2087 		mutex_exit(&impl_tokenp->s_mutex);
2088 
2089 		return (USB_SUCCESS);
2090 	}
2091 
2092 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2093 	    "usb_try_serialize_access failed: "
2094 	    "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2095 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2096 	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread);
2097 
2098 	mutex_exit(&impl_tokenp->s_mutex);
2099 
2100 	return (USB_FAILURE);
2101 }
2102 
2103 
2104 void
2105 usb_release_access(
2106 	usb_serialization_t tokenp)
2107 {
2108 	usba_serialization_impl_t *impl_tokenp =
2109 	    (usba_serialization_impl_t *)tokenp;
2110 	mutex_enter(&impl_tokenp->s_mutex);
2111 
2112 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2113 	    "usb_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
2114 	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2115 	    impl_tokenp->s_count, (void *)curthread);
2116 
2117 	ASSERT(impl_tokenp->s_count > 0);
2118 
2119 	if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
2120 		if (impl_tokenp->s_thread != curthread) {
2121 			USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2122 			    "usb_release_access: release from wrong thread");
2123 		}
2124 		ASSERT(impl_tokenp->s_thread == curthread);
2125 	}
2126 
2127 	if (--impl_tokenp->s_count == 0) {
2128 		impl_tokenp->s_thread = NULL;
2129 		cv_broadcast(&impl_tokenp->s_cv);
2130 	}
2131 	mutex_exit(&impl_tokenp->s_mutex);
2132 }
2133 
2134 
2135 /*
2136  * usb_fail_checkpoint:
2137  *	fail checkpoint as driver/device could not be quiesced
2138  */
2139 /*ARGSUSED*/
2140 void
2141 usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
2142 {
2143 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2144 
2145 	USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2146 	    "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
2147 	    ddi_get_instance(dip));
2148 
2149 	mutex_enter(&usba_device->usb_mutex);
2150 	usba_device->usb_no_cpr++;
2151 	mutex_exit(&usba_device->usb_mutex);
2152 }
2153 
2154 
2155 _NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
2156 _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
2157 /*
2158  * usba_mk_mctl:
2159  *	create a USB style M_CTL message, given an iocblk and a buffer
2160  *	returns mblk_t * on success, NULL on failure
2161  */
2162 mblk_t *
2163 usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
2164 {
2165 	mblk_t *bp1, *bp2;
2166 
2167 	if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
2168 		*((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
2169 		bp1->b_datap->db_type = M_CTL;
2170 		bp1->b_wptr += sizeof (struct iocblk);
2171 		if (buf != NULL) {
2172 			if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
2173 				bp1->b_cont = bp2;
2174 				bcopy(buf, bp2->b_datap->db_base, len);
2175 				bp2->b_wptr += len;
2176 			} else {
2177 				freemsg(bp1);
2178 				bp1 = NULL;
2179 			}
2180 		}
2181 	}
2182 
2183 	return (bp1);
2184 }
2185 
2186 
2187 #ifdef ALLOCB_TEST
2188 #undef	allocb
2189 mblk_t *
2190 usba_test_allocb(size_t size, uint_t pri)
2191 {
2192 	if (ddi_get_lbolt() & 0x1) {
2193 
2194 		return (NULL);
2195 	} else {
2196 
2197 		return (allocb(size, pri));
2198 	}
2199 }
2200 #endif
2201 
2202 
2203 /*
2204  * usb common power management for usb_mid, usb_ia and maybe other simple
2205  * drivers.
2206  */
2207 
2208 /*
2209  * functions to handle power transition for OS levels 0 -> 3
2210  */
2211 static int
2212 usb_common_pwrlvl0(dev_info_t *dip, uint8_t *pm, int *dev_state)
2213 {
2214 	int	rval;
2215 
2216 	switch (*dev_state) {
2217 	case USB_DEV_ONLINE:
2218 		/* Issue USB D3 command to the device here */
2219 		rval = usb_set_device_pwrlvl3(dip);
2220 		ASSERT(rval == USB_SUCCESS);
2221 
2222 		*dev_state = USB_DEV_PWRED_DOWN;
2223 		*pm = USB_DEV_OS_PWR_OFF;
2224 		/* FALLTHRU */
2225 	case USB_DEV_DISCONNECTED:
2226 	case USB_DEV_SUSPENDED:
2227 		/* allow a disconnected/cpr'ed device to go to low pwr */
2228 
2229 		return (USB_SUCCESS);
2230 	case USB_DEV_PWRED_DOWN:
2231 	default:
2232 		return (USB_FAILURE);
2233 	}
2234 }
2235 
2236 
2237 /* ARGSUSED */
2238 static int
2239 usb_common_pwrlvl1(dev_info_t *dip, uint8_t *pm, int *dev_state)
2240 {
2241 	int	rval;
2242 
2243 	/* Issue USB D2 command to the device here */
2244 	rval = usb_set_device_pwrlvl2(dip);
2245 	ASSERT(rval == USB_SUCCESS);
2246 
2247 	return (USB_FAILURE);
2248 }
2249 
2250 
2251 /* ARGSUSED */
2252 static int
2253 usb_common_pwrlvl2(dev_info_t *dip, uint8_t *pm, int *dev_state)
2254 {
2255 	int	rval;
2256 
2257 	/* Issue USB D1 command to the device here */
2258 	rval = usb_set_device_pwrlvl1(dip);
2259 	ASSERT(rval == USB_SUCCESS);
2260 
2261 	return (USB_FAILURE);
2262 }
2263 
2264 
2265 static int
2266 usb_common_pwrlvl3(dev_info_t *dip, uint8_t *pm, int *dev_state)
2267 {
2268 	int	rval;
2269 
2270 	switch (*dev_state) {
2271 	case USB_DEV_PWRED_DOWN:
2272 		/* Issue USB D0 command to the device here */
2273 		rval = usb_set_device_pwrlvl0(dip);
2274 		ASSERT(rval == USB_SUCCESS);
2275 
2276 		*dev_state = USB_DEV_ONLINE;
2277 		*pm = USB_DEV_OS_FULL_PWR;
2278 
2279 		/* FALLTHRU */
2280 	case USB_DEV_ONLINE:
2281 		/* we are already in full power */
2282 
2283 		/* FALLTHRU */
2284 	case USB_DEV_DISCONNECTED:
2285 	case USB_DEV_SUSPENDED:
2286 		/* allow a disconnected/cpr'ed device to go to low power */
2287 
2288 		return (USB_SUCCESS);
2289 	default:
2290 		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2291 		    "usb_common_pwrlvl3: Illegal state (%s)",
2292 		    usb_str_dev_state(*dev_state));
2293 
2294 		return (USB_FAILURE);
2295 	}
2296 }
2297 
2298 /* power management */
2299 int
2300 usba_common_power(dev_info_t *dip, uint8_t *pm, int *dev_state, int level)
2301 {
2302 	int rval = DDI_FAILURE;
2303 
2304 	switch (level) {
2305 	case USB_DEV_OS_PWR_OFF:
2306 		rval = usb_common_pwrlvl0(dip, pm, dev_state);
2307 		break;
2308 	case USB_DEV_OS_PWR_1:
2309 		rval = usb_common_pwrlvl1(dip, pm, dev_state);
2310 		break;
2311 	case USB_DEV_OS_PWR_2:
2312 		rval = usb_common_pwrlvl2(dip, pm, dev_state);
2313 		break;
2314 	case USB_DEV_OS_FULL_PWR:
2315 		rval = usb_common_pwrlvl3(dip, pm, dev_state);
2316 		break;
2317 	}
2318 
2319 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2320 }
2321 
2322 /*
2323  * register and unregister for events from our parent for usb_mid and usb_ia
2324  * and maybe other nexus driver.
2325  *
2326  * Note: The cookie fields in usba_device structure is not used. They are
2327  * used/shared by children.
2328  */
2329 void
2330 usba_common_register_events(dev_info_t *dip, uint_t if_num,
2331 	void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *))
2332 {
2333 	int rval;
2334 	usba_evdata_t *evdata;
2335 	ddi_eventcookie_t cookie;
2336 
2337 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2338 	    "usb_common_register_events:");
2339 
2340 	evdata = usba_get_evdata(dip);
2341 
2342 	/* get event cookie, discard level and icookie for now */
2343 	rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
2344 	    &cookie);
2345 
2346 	if (rval == DDI_SUCCESS) {
2347 		rval = ddi_add_event_handler(dip,
2348 		    cookie, event_cb, NULL, &evdata->ev_rm_cb_id);
2349 
2350 		if (rval != DDI_SUCCESS) {
2351 
2352 			goto fail;
2353 		}
2354 	}
2355 	rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
2356 	    &cookie);
2357 	if (rval == DDI_SUCCESS) {
2358 		rval = ddi_add_event_handler(dip, cookie, event_cb,
2359 		    NULL, &evdata->ev_ins_cb_id);
2360 
2361 		if (rval != DDI_SUCCESS) {
2362 
2363 			goto fail;
2364 		}
2365 	}
2366 	rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie);
2367 	if (rval == DDI_SUCCESS) {
2368 		rval = ddi_add_event_handler(dip,
2369 		    cookie, event_cb, NULL, &evdata->ev_suspend_cb_id);
2370 
2371 		if (rval != DDI_SUCCESS) {
2372 
2373 			goto fail;
2374 		}
2375 	}
2376 	rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie);
2377 	if (rval == DDI_SUCCESS) {
2378 		rval = ddi_add_event_handler(dip, cookie, event_cb, NULL,
2379 		    &evdata->ev_resume_cb_id);
2380 
2381 		if (rval != DDI_SUCCESS) {
2382 
2383 			goto fail;
2384 		}
2385 	}
2386 
2387 	return;
2388 
2389 
2390 fail:
2391 	usba_common_unregister_events(dip, if_num);
2392 
2393 }
2394 
2395 void
2396 usba_common_unregister_events(dev_info_t *dip, uint_t if_num)
2397 {
2398 	usba_evdata_t	*evdata;
2399 	usba_device_t	*usba_device = usba_get_usba_device(dip);
2400 	int i;
2401 
2402 	evdata = usba_get_evdata(dip);
2403 
2404 	if (evdata->ev_rm_cb_id != NULL) {
2405 		(void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
2406 		evdata->ev_rm_cb_id = NULL;
2407 	}
2408 
2409 	if (evdata->ev_ins_cb_id != NULL) {
2410 		(void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
2411 		evdata->ev_ins_cb_id = NULL;
2412 	}
2413 
2414 	if (evdata->ev_suspend_cb_id != NULL) {
2415 		(void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
2416 		evdata->ev_suspend_cb_id = NULL;
2417 	}
2418 
2419 	if (evdata->ev_resume_cb_id != NULL) {
2420 		(void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
2421 		evdata->ev_resume_cb_id = NULL;
2422 	}
2423 
2424 	/* clear event data for children, required for cfgmadm unconfigure */
2425 	mutex_enter(&usba_device->usb_mutex);
2426 	if (usb_owns_device(dip)) {
2427 		usba_free_evdata(usba_device->usb_evdata);
2428 		usba_device->usb_evdata = NULL;
2429 		usba_device->rm_cookie = NULL;
2430 		usba_device->ins_cookie = NULL;
2431 		usba_device->suspend_cookie = NULL;
2432 		usba_device->resume_cookie = NULL;
2433 	} else {
2434 		for (i = 0; i < if_num; i++) {
2435 			usba_device->usb_client_flags[usba_get_ifno(dip) + i]
2436 			    &= ~USBA_CLIENT_FLAG_EV_CBS;
2437 		}
2438 	}
2439 	mutex_exit(&usba_device->usb_mutex);
2440 }
2441