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