usbai_util.c revision 7492:2387323b838f
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#include <sys/strsun.h>
36
37extern void usba_free_evdata(usba_evdata_t *);
38
39static mblk_t *usba_get_cfg_cloud(dev_info_t *, usb_pipe_handle_t, int);
40
41/* local functions */
42static	int	usba_sync_set_cfg(dev_info_t *, usba_ph_impl_t *,
43			usba_pipe_async_req_t *, usb_flags_t);
44static int	usba_sync_set_alt_if(dev_info_t *, usba_ph_impl_t *,
45			usba_pipe_async_req_t *, usb_flags_t);
46static 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 */
77int
78usb_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 */
131int
132usb_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 */
187usb_ep_data_t *
188usb_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*/
244usb_ep_data_t *
245usb_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 */
274int
275usb_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	}
376done:
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 */
393usb_dev_descr_t *
394usb_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 */
424uchar_t *
425usb_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 */
460int
461usb_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 */
507int
508usb_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
552static int
553usba_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 */
683int
684usb_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 */
743uint_t
744usb_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 */
771int
772usb_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
810boolean_t
811usb_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 */
820boolean_t
821usba_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
834uint8_t
835usba_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 */
874int
875usb_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
916static int
917usba_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 */
980int
981usb_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 */
1049static mblk_t *
1050usba_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 */
1130int
1131usb_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 */
1287int
1288usb_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 */
1333usb_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 */
1360int
1361usb_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 */
1405int
1406usb_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 */
1479int
1480usb_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 */
1546int
1547usb_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
1589static int
1590usba_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
1601	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1602	    "usb_sync_clear_feature: "
1603	    "dip=0x%p ph=0x%p type=0x%x feature=0x%x what=0x%x fl=0x%x",
1604	    (void *)dip, (void *)ph_impl, type, feature, what, usb_flags);
1605
1606	rval = usb_clear_feature(dip, (usb_pipe_handle_t)ph_impl, type,
1607	    feature, what, usb_flags);
1608
1609	usba_release_ph_data(ph_impl);
1610
1611	return (rval);
1612}
1613
1614
1615/*
1616 * usb_async_req:
1617 *	function used to dispatch a request to the taskq
1618 *
1619 * Arguments:
1620 *	dip	- pointer to devinfo node
1621 *	func	- pointer to function issued by taskq
1622 *	flag	- USB_FLAGS_SLEEP mostly
1623 *
1624 * Return Values:
1625 *	USB_SUCCESS	- on doing a successful taskq invocation
1626 *	USB_FAILURE	- on failure
1627 *	USB_*		- refer to usbai.h
1628 */
1629int
1630usb_async_req(dev_info_t *dip,
1631		void	(*func)(void *),
1632		void	*arg,
1633		usb_flags_t flag)
1634{
1635	int tq_flag;
1636
1637	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1638	    "usb_async_req: dip=0x%p func=0x%p, arg=0x%p flag=0x%x",
1639	    (void *)dip, (void *)func, arg, flag);
1640
1641	if ((dip == NULL) || (func == NULL)) {
1642
1643		return (USB_INVALID_ARGS);
1644	}
1645	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1646	if (flag & USB_FLAGS_NOQUEUE) {
1647		tq_flag |= TQ_NOQUEUE;
1648	}
1649
1650	if (!taskq_dispatch(system_taskq, func, (void *)arg,
1651	    tq_flag)) {
1652		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1653		    "usb_async_req: failure");
1654
1655		return (USB_FAILURE);
1656	}
1657
1658	return (USB_SUCCESS);
1659}
1660
1661/*
1662 * usba_async_ph_req:
1663 *	function used to dispatch a request to the ph taskq
1664 *
1665 * Arguments:
1666 *	ph_data	- pointer to pipe handle data
1667 *	func	- pointer to function issued by taskq
1668 *	flag	- USB_FLAGS_SLEEP or USB_FLAGS_NOSLEEP
1669 *
1670 * Return Values:
1671 *	USB_SUCCESS	- on doing a successful taskq invocation
1672 *	USB_FAILURE	- on failure
1673 *	USB_*		- refer to usbai.h
1674 *
1675 * Note:
1676 *	If the caller specified  USB_FLAGS_NOSLEEP, it must be
1677 *	capable of reliably recovering from a failure return
1678 */
1679int
1680usba_async_ph_req(usba_pipe_handle_data_t *ph_data,
1681		void	(*func)(void *),
1682		void	*arg,
1683		usb_flags_t flag)
1684{
1685	int	tq_flag;
1686	taskq_t *taskq;
1687
1688	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1689	    "usba_async_ph_req: ph_data=0x%p func=0x%p, arg=0x%p flag=0x%x",
1690	    (void *)ph_data, (void *)func, arg, flag);
1691
1692	if (func == NULL) {
1693
1694		return (USB_INVALID_ARGS);
1695	}
1696
1697	tq_flag = (flag & USB_FLAGS_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
1698
1699	if (ph_data && ph_data->p_taskq) {
1700		taskq = ph_data->p_taskq;
1701	} else {
1702		taskq = system_taskq;
1703		tq_flag |= TQ_NOQUEUE;
1704	}
1705
1706	if (!taskq_dispatch(taskq, func, (void *)arg, tq_flag)) {
1707		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
1708		    "usba_async_ph_req: failure");
1709
1710		return (USB_FAILURE);
1711	}
1712
1713	return (USB_SUCCESS);
1714}
1715
1716
1717/*
1718 * utility functions to display CR, CB, return values
1719 */
1720typedef struct conv_table {
1721	int		what;
1722	const char	*name;
1723} conv_table_t;
1724
1725static const char *
1726usba_get_name(conv_table_t *conv_table, int value)
1727{
1728	int i;
1729	for (i = 0; conv_table[i].name != NULL; i++) {
1730		if (conv_table[i].what == value) {
1731
1732			return (conv_table[i].name);
1733		}
1734	}
1735
1736	return ("unknown");
1737}
1738
1739
1740static conv_table_t cr_table[] = {
1741	{ USB_CR_OK,		"<no errors detected>" },
1742	{ USB_CR_CRC,		"<crc error detected>" },
1743	{ USB_CR_BITSTUFFING,	"<Bit stuffing violation>" },
1744	{ USB_CR_DATA_TOGGLE_MM, "<Data toggle PID did not match>" },
1745	{ USB_CR_STALL, 	"<Endpoint returned stall PID>" },
1746	{ USB_CR_DEV_NOT_RESP,	"<Device not responding>" },
1747	{ USB_CR_PID_CHECKFAILURE, "<Check bits on PID failed>" },
1748	{ USB_CR_UNEXP_PID,	"<Receive PID was not valid>" },
1749	{ USB_CR_DATA_OVERRUN,	"<Data size exceeded>" },
1750	{ USB_CR_DATA_UNDERRUN, "<Less data recieved than requested>" },
1751	{ USB_CR_BUFFER_OVERRUN, "<Memory write can't keep up>" },
1752	{ USB_CR_BUFFER_UNDERRUN, "<Buffer underrun>" },
1753	{ USB_CR_TIMEOUT,	"<Command timed out>" },
1754	{ USB_CR_NOT_ACCESSED,	"<Not accessed by hardware>" },
1755	{ USB_CR_NO_RESOURCES,	"<No resources>" },
1756	{ USB_CR_UNSPECIFIED_ERR, "<Unspecified usba or hcd error>" },
1757	{ USB_CR_STOPPED_POLLING, "<Intr/ISOC IN polling stopped>" },
1758	{ USB_CR_PIPE_CLOSING,	"<Intr/ISOC IN pipe being closed>" },
1759	{ USB_CR_PIPE_RESET,	"<Intr/ISOC IN pipe reset>" },
1760	{ USB_CR_NOT_SUPPORTED, "<Command not supported>" },
1761	{ USB_CR_FLUSHED,	"<Req was flushed>" },
1762	{ USB_CR_HC_HARDWARE_ERR, "<USB host controller error>" },
1763	{ 0,			NULL }
1764};
1765
1766const char *
1767usb_str_cr(usb_cr_t cr)
1768{
1769	return (usba_get_name(cr_table, cr));
1770}
1771
1772
1773static conv_table_t cb_flags_table[] = {
1774	{ USB_CB_NO_INFO,	"<callback processed>" },
1775	{ USB_CB_STALL_CLEARED, "<stall cleared>" },
1776	{ USB_CB_FUNCTIONAL_STALL, "<functional stall>" },
1777	{ USB_CB_PROTOCOL_STALL, "<protocol stall>" },
1778	{ USB_CB_RESET_PIPE,	"<pipe reset>" },
1779	{ USB_CB_ASYNC_REQ_FAILED, "<thread could not be started>" },
1780	{ USB_CB_NO_RESOURCES,	"<no resources>" },
1781	{ USB_CB_SUBMIT_FAILED, "<submit failed>" },
1782	{ USB_CB_INTR_CONTEXT,	"<Callback executing in interrupt context>" },
1783	{ 0,			NULL }
1784};
1785
1786/*ARGSUSED*/
1787char *
1788usb_str_cb_flags(usb_cb_flags_t cb_flags, char *buffer, size_t length)
1789{
1790	int i;
1791	buffer[0] = '\0';
1792	if (cb_flags == USB_CB_NO_INFO) {
1793		(void) strncpy(buffer, cb_flags_table[0].name, length);
1794	} else {
1795		for (i = 0; cb_flags_table[i].name != NULL; i++) {
1796			if (cb_flags & cb_flags_table[i].what) {
1797				(void) strncpy(&buffer[strlen(buffer)],
1798				    cb_flags_table[0].name,
1799				    length - strlen(buffer) - 1);
1800			}
1801		}
1802	}
1803
1804	return (buffer);
1805}
1806
1807
1808static conv_table_t pipe_state_table[] = {
1809	{ USB_PIPE_STATE_CLOSED,	"<closed>" },
1810	{ USB_PIPE_STATE_IDLE,		"<idle>" },
1811	{ USB_PIPE_STATE_ACTIVE,	"<active>" },
1812	{ USB_PIPE_STATE_ERROR,		"<error>" },
1813	{ USB_PIPE_STATE_CLOSING,	"<closing>" },
1814	{ 0,				NULL }
1815};
1816
1817const char *
1818usb_str_pipe_state(usb_pipe_state_t state)
1819{
1820	return (usba_get_name(pipe_state_table, state));
1821}
1822
1823
1824static conv_table_t dev_state[] = {
1825	{ USB_DEV_ONLINE,	"<online>" },
1826	{ USB_DEV_DISCONNECTED,	"<disconnected>" },
1827	{ USB_DEV_SUSPENDED,	"<suspended>" },
1828	{ USB_DEV_PWRED_DOWN,	"<powered down>" },
1829	{ 0,			NULL }
1830};
1831
1832const char *
1833usb_str_dev_state(int state)
1834{
1835	return (usba_get_name(dev_state, state));
1836}
1837
1838
1839static conv_table_t rval_table[] = {
1840	{ USB_SUCCESS,		"<success>" },
1841	{ USB_FAILURE,		"<failure>" },
1842	{ USB_NO_RESOURCES,	"<no resources>" },
1843	{ USB_NO_BANDWIDTH,	"<no bandwidth>" },
1844	{ USB_NOT_SUPPORTED,	"<not supported>" },
1845	{ USB_PIPE_ERROR,	"<pipe error>" },
1846	{ USB_INVALID_PIPE,	"<invalid pipe>" },
1847	{ USB_NO_FRAME_NUMBER,	"<no frame number>" },
1848	{ USB_INVALID_START_FRAME, "<invalid frame>" },
1849	{ USB_HC_HARDWARE_ERROR, "<hw error>" },
1850	{ USB_INVALID_REQUEST,	"<invalid request>" },
1851	{ USB_INVALID_CONTEXT,	"<invalid context>" },
1852	{ USB_INVALID_VERSION,	"<invalid version>" },
1853	{ USB_INVALID_ARGS,	"<invalid args>" },
1854	{ USB_INVALID_PERM,	"<invalid perms>" },
1855	{ USB_BUSY,		"<busy>" },
1856	{ 0,			NULL }
1857};
1858
1859const char *
1860usb_str_rval(int rval)
1861{
1862	return (usba_get_name(rval_table, rval));
1863}
1864
1865
1866/*
1867 * function to convert USB return values to close errno
1868 */
1869static struct usb_rval2errno_entry {
1870	int	rval;
1871	int	Errno;
1872} usb_rval2errno_table[] = {
1873	{ USB_SUCCESS,			0	},
1874	{ USB_FAILURE,			EIO	},
1875	{ USB_NO_RESOURCES,		ENOMEM	},
1876	{ USB_NO_BANDWIDTH,		EAGAIN	},
1877	{ USB_NOT_SUPPORTED,		ENOTSUP },
1878	{ USB_PIPE_ERROR,		EIO	},
1879	{ USB_INVALID_PIPE,		EINVAL	},
1880	{ USB_NO_FRAME_NUMBER,		EINVAL	},
1881	{ USB_INVALID_START_FRAME,	EINVAL	},
1882	{ USB_HC_HARDWARE_ERROR,	EIO	},
1883	{ USB_INVALID_REQUEST,		EINVAL	},
1884	{ USB_INVALID_CONTEXT,		EINVAL	},
1885	{ USB_INVALID_VERSION,		EINVAL	},
1886	{ USB_INVALID_ARGS,		EINVAL	},
1887	{ USB_INVALID_PERM,		EACCES	},
1888	{ USB_BUSY,			EBUSY	},
1889};
1890
1891#define	USB_RVAL2ERRNO_TABLE_SIZE (sizeof (usb_rval2errno_table) / \
1892			sizeof (struct usb_rval2errno_entry))
1893int
1894usb_rval2errno(int rval)
1895{
1896	int i;
1897
1898	for (i = 0; i < USB_RVAL2ERRNO_TABLE_SIZE; i++) {
1899		if (usb_rval2errno_table[i].rval == rval) {
1900
1901			return (usb_rval2errno_table[i].Errno);
1902		}
1903	}
1904
1905	return (EIO);
1906}
1907
1908
1909/*
1910 * serialization
1911 */
1912usb_serialization_t
1913usb_init_serialization(
1914	dev_info_t	*dip,
1915	uint_t		flag)
1916{
1917	usba_serialization_impl_t *impl_tokenp = kmem_zalloc(
1918	    sizeof (usba_serialization_impl_t), KM_SLEEP);
1919	usba_device_t	*usba_device;
1920	ddi_iblock_cookie_t cookie = NULL;
1921
1922	if (dip) {
1923		usba_device = usba_get_usba_device(dip);
1924		cookie = usba_hcdi_get_hcdi(
1925		    usba_device->usb_root_hub_dip)->hcdi_iblock_cookie;
1926	}
1927	impl_tokenp->s_dip = dip;
1928	impl_tokenp->s_flag = flag;
1929	mutex_init(&impl_tokenp->s_mutex, NULL, MUTEX_DRIVER, cookie);
1930	cv_init(&impl_tokenp->s_cv, NULL, CV_DRIVER, NULL);
1931
1932	return ((usb_serialization_t)impl_tokenp);
1933}
1934
1935
1936void
1937usb_fini_serialization(
1938	usb_serialization_t tokenp)
1939{
1940	usba_serialization_impl_t *impl_tokenp;
1941
1942	if (tokenp) {
1943		impl_tokenp = (usba_serialization_impl_t *)tokenp;
1944		ASSERT(impl_tokenp->s_count == 0);
1945		cv_destroy(&impl_tokenp->s_cv);
1946		mutex_destroy(&impl_tokenp->s_mutex);
1947		kmem_free(impl_tokenp, sizeof (usba_serialization_impl_t));
1948	}
1949}
1950
1951
1952/*
1953 * usb_serialize_access() permits single threaded access.
1954 *
1955 * If tokenp is initialized with USB_INIT_SER_CHECK_SAME_THREAD,
1956 * it is reentrant with respect to thread. The thread must
1957 * hold and release the same number of times.
1958 *
1959 * If tokenp is initialized without USB_INIT_SER_CHECK_SAME_THREAD,
1960 * it is not reentrant by the same thread. It is something like
1961 * a semaphore.
1962 */
1963int
1964usb_serialize_access(
1965	usb_serialization_t tokenp, uint_t how_to_wait, uint_t delta_timeout)
1966{
1967	int			rval = 1;	/* Must be initialized > 0 */
1968	clock_t			abs_timeout;
1969	usba_serialization_impl_t *impl_tokenp;
1970
1971	impl_tokenp = (usba_serialization_impl_t *)tokenp;
1972
1973	/*
1974	 * Convert delta timeout in ms to absolute timeout in ticks, if used.
1975	 */
1976	if ((how_to_wait == USB_TIMEDWAIT) ||
1977	    (how_to_wait == USB_TIMEDWAIT_SIG)) {
1978		/* Convert timeout arg (in ms) to hz */
1979		abs_timeout = ddi_get_lbolt() +
1980		    drv_usectohz(delta_timeout * 1000);
1981	}
1982
1983	/* Get mutex after calc abs time, to count time waiting for mutex. */
1984	mutex_enter(&impl_tokenp->s_mutex);
1985
1986	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
1987	    "usb_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p, "
1988	    "flg=0x%x, abs_tmo=0x%lx",
1989	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
1990	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread,
1991	    how_to_wait, abs_timeout);
1992
1993	if ((impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0 ||
1994	    impl_tokenp->s_thread != curthread) {
1995
1996		/*
1997		 * There are three ways to break out of the loop:
1998		 * 1) Condition met (s_count == 0) - higher prio test
1999		 * 2) kill(2) signal received (rval == 0)
2000		 * 3) timeout occurred (rval == -1)
2001		 * If condition met, whether or not signal or timeout occurred
2002		 * take access.  If condition not met, check other exit means.
2003		 */
2004		while (impl_tokenp->s_count != 0) {
2005
2006			/* cv_timedwait* returns -1 on timeout. */
2007			/* cv_wait*_sig returns 0 on (kill(2)) signal. */
2008			if (rval <= 0) {
2009				mutex_exit(&impl_tokenp->s_mutex);
2010				USB_DPRINTF_L4(DPRINT_MASK_USBA,
2011				    usbai_log_handle,
2012				    "usb_serialize_access: "
2013				    "tok=0x%p exit due to %s",
2014				    (void *)impl_tokenp,
2015				    ((rval == 0) ? "signal" : "timeout"));
2016
2017				return (rval);
2018			}
2019
2020			switch (how_to_wait) {
2021			default:
2022				how_to_wait = USB_WAIT;
2023				/* FALLTHROUGH */
2024			case USB_WAIT:
2025				cv_wait(&impl_tokenp->s_cv,
2026				    &impl_tokenp->s_mutex);
2027				break;
2028			case USB_WAIT_SIG:
2029				rval = cv_wait_sig(&impl_tokenp->s_cv,
2030				    &impl_tokenp->s_mutex);
2031				break;
2032			case USB_TIMEDWAIT:
2033				rval = cv_timedwait(&impl_tokenp->s_cv,
2034				    &impl_tokenp->s_mutex, abs_timeout);
2035				break;
2036			case USB_TIMEDWAIT_SIG:
2037				rval = cv_timedwait_sig(&impl_tokenp->s_cv,
2038				    &impl_tokenp->s_mutex, abs_timeout);
2039				break;
2040			}
2041		}
2042
2043		impl_tokenp->s_thread = curthread;
2044	}
2045	impl_tokenp->s_count++;
2046
2047	ASSERT(!(impl_tokenp->s_count > 1 &&
2048	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) == 0));
2049
2050	mutex_exit(&impl_tokenp->s_mutex);
2051
2052	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2053	    "usb_serialize_access exit: tok=0x%p thr=0x%p", (void *)impl_tokenp,
2054	    (void *)curthread);
2055
2056	return (1);
2057}
2058
2059
2060/*ARGSUSED*/
2061int
2062usb_try_serialize_access(
2063	usb_serialization_t tokenp, uint_t flag)
2064{
2065	usba_serialization_impl_t *impl_tokenp =
2066	    (usba_serialization_impl_t *)tokenp;
2067	mutex_enter(&impl_tokenp->s_mutex);
2068
2069	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2070	    "usb_try_serialize_access: tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2071	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2072	    impl_tokenp->s_count, (void *)curthread);
2073
2074	/*
2075	 * If lock is not taken (s_count is 0), take it.
2076	 * If lock is already taken, the thread is owner and lock
2077	 * is reentrant, take it.
2078	 * Otherwise, fail the access.
2079	 */
2080	if (!impl_tokenp->s_count || ((impl_tokenp->s_thread == curthread) &&
2081	    (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD))) {
2082		impl_tokenp->s_thread = curthread;
2083		impl_tokenp->s_count++;
2084
2085		USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2086		    "usb_try_serialize_access success: tok=0x%p",
2087		    (void *)impl_tokenp);
2088		mutex_exit(&impl_tokenp->s_mutex);
2089
2090		return (USB_SUCCESS);
2091	}
2092
2093	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2094	    "usb_try_serialize_access failed: "
2095	    "tok=0x%p dip=0x%p cnt=%d thr=0x%p",
2096	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2097	    impl_tokenp->s_count, (void *)impl_tokenp->s_thread);
2098
2099	mutex_exit(&impl_tokenp->s_mutex);
2100
2101	return (USB_FAILURE);
2102}
2103
2104
2105void
2106usb_release_access(
2107	usb_serialization_t tokenp)
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_release_access: tok=0x%p dip=0x%p count=%d thr=0x%p",
2115	    (void *)impl_tokenp, (void *)impl_tokenp->s_dip,
2116	    impl_tokenp->s_count, (void *)curthread);
2117
2118	ASSERT(impl_tokenp->s_count > 0);
2119
2120	if (impl_tokenp->s_flag & USB_INIT_SER_CHECK_SAME_THREAD) {
2121		if (impl_tokenp->s_thread != curthread) {
2122			USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2123			    "usb_release_access: release from wrong thread");
2124		}
2125		ASSERT(impl_tokenp->s_thread == curthread);
2126	}
2127
2128	if (--impl_tokenp->s_count == 0) {
2129		impl_tokenp->s_thread = NULL;
2130		cv_broadcast(&impl_tokenp->s_cv);
2131	}
2132	mutex_exit(&impl_tokenp->s_mutex);
2133}
2134
2135
2136/*
2137 * usb_fail_checkpoint:
2138 *	fail checkpoint as driver/device could not be quiesced
2139 */
2140/*ARGSUSED*/
2141void
2142usb_fail_checkpoint(dev_info_t *dip, usb_flags_t flags)
2143{
2144	usba_device_t	*usba_device = usba_get_usba_device(dip);
2145
2146	USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2147	    "usb_fail_checkpoint: %s%d", ddi_driver_name(dip),
2148	    ddi_get_instance(dip));
2149
2150	mutex_enter(&usba_device->usb_mutex);
2151	usba_device->usb_no_cpr++;
2152	mutex_exit(&usba_device->usb_mutex);
2153}
2154
2155
2156_NOTE(SCHEME_PROTECTS_DATA("unique per call", iocblk))
2157_NOTE(SCHEME_PROTECTS_DATA("unique per call", datab))
2158/*
2159 * usba_mk_mctl:
2160 *	create a USB style M_CTL message, given an iocblk and a buffer
2161 *	returns mblk_t * on success, NULL on failure
2162 */
2163mblk_t *
2164usba_mk_mctl(struct iocblk mctlmsg, void *buf, size_t len)
2165{
2166	mblk_t *bp1, *bp2;
2167
2168	if ((bp1 = allocb(sizeof (struct iocblk), BPRI_HI)) != NULL) {
2169		/* LINTED E_BAD_PTR_CAST_ALIGN */
2170		*((struct iocblk *)bp1->b_datap->db_base) = mctlmsg;
2171		bp1->b_datap->db_type = M_CTL;
2172		bp1->b_wptr += sizeof (struct iocblk);
2173		if (buf != NULL) {
2174			if ((bp2 = allocb(len, BPRI_HI)) != NULL) {
2175				bp1->b_cont = bp2;
2176				bcopy(buf, bp2->b_datap->db_base, len);
2177				bp2->b_wptr += len;
2178			} else {
2179				freemsg(bp1);
2180				bp1 = NULL;
2181			}
2182		}
2183	}
2184
2185	return (bp1);
2186}
2187
2188
2189#ifdef ALLOCB_TEST
2190#undef	allocb
2191mblk_t *
2192usba_test_allocb(size_t size, uint_t pri)
2193{
2194	if (ddi_get_lbolt() & 0x1) {
2195
2196		return (NULL);
2197	} else {
2198
2199		return (allocb(size, pri));
2200	}
2201}
2202#endif
2203
2204
2205/*
2206 * usb common power management for usb_mid, usb_ia and maybe other simple
2207 * drivers.
2208 */
2209
2210/*
2211 * functions to handle power transition for OS levels 0 -> 3
2212 */
2213static int
2214usb_common_pwrlvl0(dev_info_t *dip, uint8_t *pm, int *dev_state)
2215{
2216	int	rval;
2217
2218	switch (*dev_state) {
2219	case USB_DEV_ONLINE:
2220		/* Issue USB D3 command to the device here */
2221		rval = usb_set_device_pwrlvl3(dip);
2222		ASSERT(rval == USB_SUCCESS);
2223
2224		*dev_state = USB_DEV_PWRED_DOWN;
2225		*pm = USB_DEV_OS_PWR_OFF;
2226		/* FALLTHRU */
2227	case USB_DEV_DISCONNECTED:
2228	case USB_DEV_SUSPENDED:
2229		/* allow a disconnected/cpr'ed device to go to low pwr */
2230
2231		return (USB_SUCCESS);
2232	case USB_DEV_PWRED_DOWN:
2233	default:
2234		return (USB_FAILURE);
2235	}
2236}
2237
2238
2239/* ARGSUSED */
2240static int
2241usb_common_pwrlvl1(dev_info_t *dip, uint8_t *pm, int *dev_state)
2242{
2243	int	rval;
2244
2245	/* Issue USB D2 command to the device here */
2246	rval = usb_set_device_pwrlvl2(dip);
2247	ASSERT(rval == USB_SUCCESS);
2248
2249	return (USB_FAILURE);
2250}
2251
2252
2253/* ARGSUSED */
2254static int
2255usb_common_pwrlvl2(dev_info_t *dip, uint8_t *pm, int *dev_state)
2256{
2257	int	rval;
2258
2259	/* Issue USB D1 command to the device here */
2260	rval = usb_set_device_pwrlvl1(dip);
2261	ASSERT(rval == USB_SUCCESS);
2262
2263	return (USB_FAILURE);
2264}
2265
2266
2267static int
2268usb_common_pwrlvl3(dev_info_t *dip, uint8_t *pm, int *dev_state)
2269{
2270	int	rval;
2271
2272	switch (*dev_state) {
2273	case USB_DEV_PWRED_DOWN:
2274		/* Issue USB D0 command to the device here */
2275		rval = usb_set_device_pwrlvl0(dip);
2276		ASSERT(rval == USB_SUCCESS);
2277
2278		*dev_state = USB_DEV_ONLINE;
2279		*pm = USB_DEV_OS_FULL_PWR;
2280
2281		/* FALLTHRU */
2282	case USB_DEV_ONLINE:
2283		/* we are already in full power */
2284
2285		/* FALLTHRU */
2286	case USB_DEV_DISCONNECTED:
2287	case USB_DEV_SUSPENDED:
2288		/* allow a disconnected/cpr'ed device to go to low power */
2289
2290		return (USB_SUCCESS);
2291	default:
2292		USB_DPRINTF_L2(DPRINT_MASK_USBA, usbai_log_handle,
2293		    "usb_common_pwrlvl3: Illegal state (%s)",
2294		    usb_str_dev_state(*dev_state));
2295
2296		return (USB_FAILURE);
2297	}
2298}
2299
2300/* power management */
2301int
2302usba_common_power(dev_info_t *dip, uint8_t *pm, int *dev_state, int level)
2303{
2304	int rval = DDI_FAILURE;
2305
2306	switch (level) {
2307	case USB_DEV_OS_PWR_OFF:
2308		rval = usb_common_pwrlvl0(dip, pm, dev_state);
2309		break;
2310	case USB_DEV_OS_PWR_1:
2311		rval = usb_common_pwrlvl1(dip, pm, dev_state);
2312		break;
2313	case USB_DEV_OS_PWR_2:
2314		rval = usb_common_pwrlvl2(dip, pm, dev_state);
2315		break;
2316	case USB_DEV_OS_FULL_PWR:
2317		rval = usb_common_pwrlvl3(dip, pm, dev_state);
2318		break;
2319	}
2320
2321	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2322}
2323
2324/*
2325 * register and unregister for events from our parent for usb_mid and usb_ia
2326 * and maybe other nexus driver.
2327 *
2328 * Note: The cookie fields in usba_device structure is not used. They are
2329 * used/shared by children.
2330 */
2331void
2332usba_common_register_events(dev_info_t *dip, uint_t if_num,
2333	void (*event_cb)(dev_info_t *, ddi_eventcookie_t, void *, void *))
2334{
2335	int rval;
2336	usba_evdata_t *evdata;
2337	ddi_eventcookie_t cookie;
2338
2339	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
2340	    "usb_common_register_events:");
2341
2342	evdata = usba_get_evdata(dip);
2343
2344	/* get event cookie, discard level and icookie for now */
2345	rval = ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
2346	    &cookie);
2347
2348	if (rval == DDI_SUCCESS) {
2349		rval = ddi_add_event_handler(dip,
2350		    cookie, event_cb, NULL, &evdata->ev_rm_cb_id);
2351
2352		if (rval != DDI_SUCCESS) {
2353
2354			goto fail;
2355		}
2356	}
2357	rval = ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
2358	    &cookie);
2359	if (rval == DDI_SUCCESS) {
2360		rval = ddi_add_event_handler(dip, cookie, event_cb,
2361		    NULL, &evdata->ev_ins_cb_id);
2362
2363		if (rval != DDI_SUCCESS) {
2364
2365			goto fail;
2366		}
2367	}
2368	rval = ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, &cookie);
2369	if (rval == DDI_SUCCESS) {
2370		rval = ddi_add_event_handler(dip,
2371		    cookie, event_cb, NULL, &evdata->ev_suspend_cb_id);
2372
2373		if (rval != DDI_SUCCESS) {
2374
2375			goto fail;
2376		}
2377	}
2378	rval = ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, &cookie);
2379	if (rval == DDI_SUCCESS) {
2380		rval = ddi_add_event_handler(dip, cookie, event_cb, NULL,
2381		    &evdata->ev_resume_cb_id);
2382
2383		if (rval != DDI_SUCCESS) {
2384
2385			goto fail;
2386		}
2387	}
2388
2389	return;
2390
2391
2392fail:
2393	usba_common_unregister_events(dip, if_num);
2394
2395}
2396
2397void
2398usba_common_unregister_events(dev_info_t *dip, uint_t if_num)
2399{
2400	usba_evdata_t	*evdata;
2401	usba_device_t	*usba_device = usba_get_usba_device(dip);
2402	int i;
2403
2404	evdata = usba_get_evdata(dip);
2405
2406	if (evdata->ev_rm_cb_id != NULL) {
2407		(void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
2408		evdata->ev_rm_cb_id = NULL;
2409	}
2410
2411	if (evdata->ev_ins_cb_id != NULL) {
2412		(void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
2413		evdata->ev_ins_cb_id = NULL;
2414	}
2415
2416	if (evdata->ev_suspend_cb_id != NULL) {
2417		(void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
2418		evdata->ev_suspend_cb_id = NULL;
2419	}
2420
2421	if (evdata->ev_resume_cb_id != NULL) {
2422		(void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
2423		evdata->ev_resume_cb_id = NULL;
2424	}
2425
2426	/* clear event data for children, required for cfgmadm unconfigure */
2427	mutex_enter(&usba_device->usb_mutex);
2428	if (usb_owns_device(dip)) {
2429		usba_free_evdata(usba_device->usb_evdata);
2430		usba_device->usb_evdata = NULL;
2431		usba_device->rm_cookie = NULL;
2432		usba_device->ins_cookie = NULL;
2433		usba_device->suspend_cookie = NULL;
2434		usba_device->resume_cookie = NULL;
2435	} else {
2436		for (i = 0; i < if_num; i++) {
2437			usba_device->usb_client_flags[usba_get_ifno(dip) + i]
2438			    &= ~USBA_CLIENT_FLAG_EV_CBS;
2439		}
2440	}
2441	mutex_exit(&usba_device->usb_mutex);
2442}
2443