xref: /onnv-gate/usr/src/uts/common/io/usb/clients/wusb_ca/wusb_ca.c (revision 9430:637732b28916)
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  * WUSB cable association driver
28  *
29  * This driver implements the cable association mechanism defined in
30  * "Association Models Supplement to the Certified Wireless Universal
31  * Serial Bus Specification 1.0". Cable association compliant devices,
32  * i.e. with bInterfaceClass=0xEF, bInterfaceSubClass=0x03 and
33  * bInterfaceProtocol=0x01(compatible names: "usbif,classef.3.1") will
34  * be supported by this driver.
35  *
36  * The Cable Association Model uses the USB Cable-Based Association
37  * Framework (CBAF). The basic operation under this framework is:
38  *
39  * - The user connects the device to the host using a USB cable.
40  *
41  * - The host detects that the device supports the CBAF and it is capable
42  *   of configuring WUSB CC(Connection Context).
43  *
44  * - The host sends its CHID to the device, along with other information
45  *
46  * - If the device has a valid CC with a matching CHID, the device will
47  *   respond to the host with the CDID from the CC.
48  *
49  * - As of this driver implementation, no matter if the CDID returned
50  *   from the device matches the CDID in the host's copy of CC, we choose
51  *   to skip further explicit user conditioning, generate a new CC and send
52  *   it to the device.
53  *
54  * - Upon receiving the CC, the device must store the CC in non-volatile
55  *   memory, replacing any existing CC with a matching CHID if it exists.
56  *
57  * - First time association is complete: Host has securely transferred the CC
58  *   to the device
59  *
60  * CBAF requires device to use the default control endpoint to exchange
61  * requests and data with host. Three control requests are defined by spec
62  * and supported by this driver:
63  *	- GET_ASSOCIATION_INFORMATION
64  *	- GET_ASSOCIATION_REQUEST
65  *	- SET_ASSOCIATION_RESPONSE
66  *
67  */
68 
69 #if defined(lint) && !defined(DEBUG)
70 #define	DEBUG
71 #endif
72 
73 #define	USBDRV_MAJOR_VER	2
74 #define	USBDRV_MINOR_VER	0
75 
76 #include <sys/usb/usba.h>
77 #include <sys/stream.h>
78 #include <sys/strsun.h>
79 #include <sys/usb/clients/wusb_ca/wusb_ca_priv.h>
80 #include <sys/usb/clients/wusb_ca/wusb_ca.h>
81 
82 
83 uint_t	wusb_ca_errlevel = USB_LOG_L4;
84 uint_t  wusb_ca_errmask   = (uint_t)PRINT_MASK_ALL;
85 uint_t  wusb_ca_instance_debug = (uint_t)-1;
86 
87 /*
88  * Function Prototypes
89  */
90 static int	wusb_ca_attach(dev_info_t *, ddi_attach_cmd_t);
91 static int	wusb_ca_detach(dev_info_t *, ddi_detach_cmd_t);
92 static int	wusb_ca_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
93 static int	wusb_ca_cleanup(dev_info_t *, wusb_ca_state_t *);
94 static int	wusb_ca_open(dev_t *, int, int, cred_t *);
95 static int	wusb_ca_close(dev_t, int, int, cred_t *);
96 static int	wusb_ca_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
97 static int	wusb_ca_disconnect_callback(dev_info_t *);
98 static int	wusb_ca_reconnect_callback(dev_info_t *);
99 static void	wusb_ca_restore_device_state(dev_info_t *, wusb_ca_state_t *);
100 
101 static int	wusb_ca_cpr_suspend(dev_info_t *);
102 static void	wusb_ca_cpr_resume(dev_info_t *);
103 static int	wusb_ca_pm_busy_component(wusb_ca_state_t *);
104 static void	wusb_ca_pm_idle_component(wusb_ca_state_t *);
105 static int	wusb_ca_power(dev_info_t *, int, int);
106 static void	wusb_ca_init_power_mgmt(wusb_ca_state_t *);
107 static void	wusb_ca_destroy_power_mgmt(wusb_ca_state_t *);
108 
109 static int	wusb_ca_serialize_access(wusb_ca_state_t *, boolean_t);
110 static void	wusb_ca_release_access(wusb_ca_state_t *);
111 static int	wusb_ca_check_same_device(wusb_ca_state_t *);
112 
113 static mblk_t	*trans_from_host_info(wusb_cbaf_host_info_t *);
114 static mblk_t	*trans_from_cc_data(wusb_cbaf_cc_data_t *);
115 static mblk_t	*trans_from_cc_fail(wusb_cbaf_cc_fail_t *);
116 static int	trans_to_device_info(wusb_ca_state_t *, mblk_t *,
117 		wusb_cbaf_device_info_t *);
118 
119 /* _NOTE is an advice for locklint.  Locklint checks lock use for deadlocks. */
120 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
121 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf))
122 _NOTE(SCHEME_PROTECTS_DATA("unique per call", msgb))
123 /* module loading stuff */
124 struct cb_ops wusb_ca_cb_ops = {
125 	wusb_ca_open,		/* open  */
126 	wusb_ca_close,		/* close */
127 	nulldev,		/* strategy */
128 	nulldev,		/* print */
129 	nulldev,		/* dump */
130 	nodev,			/* read */
131 	nodev,			/* write */
132 	wusb_ca_ioctl,		/* ioctl */
133 	nulldev,		/* devmap */
134 	nodev,			/* mmap */
135 	nodev,			/* segmap */
136 	nochpoll,		/* poll */
137 	ddi_prop_op,		/* cb_prop_op */
138 	NULL,			/* streamtab  */
139 	D_MP
140 };
141 
142 static struct dev_ops wusb_ca_ops = {
143 	DEVO_REV,		/* devo_rev, */
144 	0,			/* refcnt  */
145 	wusb_ca_info,		/* info */
146 	nulldev,		/* identify */
147 	nulldev,		/* probe */
148 	wusb_ca_attach,		/* attach */
149 	wusb_ca_detach,		/* detach */
150 	nodev,			/* reset */
151 	&wusb_ca_cb_ops,	/* driver operations */
152 	NULL,			/* bus operations */
153 	wusb_ca_power,		/* power */
154 	ddi_quiesce_not_needed, /* quiesce */
155 };
156 
157 static struct modldrv wusb_ca_modldrv =	{
158 	&mod_driverops,
159 	"WUSB Cable Association driver",
160 	&wusb_ca_ops
161 };
162 
163 static struct modlinkage modlinkage = {
164 	MODREV_1,
165 	&wusb_ca_modldrv,
166 	NULL
167 };
168 
169 /* local variables */
170 
171 /* Soft state structures */
172 #define	WUSB_CA_INITIAL_SOFT_SPACE	1
173 static void *wusb_ca_statep;
174 
175 
176 /*
177  * Module-wide initialization routine.
178  */
179 int
_init(void)180 _init(void)
181 {
182 	int rval;
183 
184 	if ((rval = ddi_soft_state_init(&wusb_ca_statep,
185 	    sizeof (wusb_ca_state_t), WUSB_CA_INITIAL_SOFT_SPACE)) != 0) {
186 
187 		return (rval);
188 	}
189 
190 	if ((rval = mod_install(&modlinkage)) != 0) {
191 		ddi_soft_state_fini(&wusb_ca_statep);
192 	}
193 
194 	return (rval);
195 }
196 
197 
198 /*
199  * Module-wide tear-down routine.
200  */
201 int
_fini(void)202 _fini(void)
203 {
204 	int rval;
205 
206 	if ((rval = mod_remove(&modlinkage)) != 0) {
207 
208 		return (rval);
209 	}
210 
211 	ddi_soft_state_fini(&wusb_ca_statep);
212 
213 	return (rval);
214 }
215 
216 
217 int
_info(struct modinfo * modinfop)218 _info(struct modinfo *modinfop)
219 {
220 	return (mod_info(&modlinkage, modinfop));
221 }
222 
223 
224 /*
225  * wusb_ca_info:
226  *	Get minor number, soft state structure, etc.
227  */
228 /*ARGSUSED*/
229 static int
wusb_ca_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)230 wusb_ca_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
231 			void *arg, void **result)
232 {
233 	wusb_ca_state_t	*wusb_cap;
234 	int error = DDI_FAILURE;
235 
236 	switch (infocmd) {
237 	case DDI_INFO_DEVT2DEVINFO:
238 		if ((wusb_cap = ddi_get_soft_state(wusb_ca_statep,
239 		    getminor((dev_t)arg))) != NULL) {
240 			*result = wusb_cap->wusb_ca_dip;
241 			if (*result != NULL) {
242 				error = DDI_SUCCESS;
243 			}
244 		} else {
245 			*result = NULL;
246 		}
247 		break;
248 	case DDI_INFO_DEVT2INSTANCE:
249 		*result = (void *)(uintptr_t)getminor((dev_t)arg);
250 		error = DDI_SUCCESS;
251 		break;
252 	default:
253 		break;
254 	}
255 
256 	return (error);
257 }
258 
259 
260 /*
261  * wusb_ca_attach:
262  *	Attach or resume.
263  *
264  *	For attach, initialize state and device, including:
265  *		state variables, locks, device node
266  *		device registration with system
267  *		power management, hotplugging
268  *	For resume, restore device and state
269  */
270 static int
wusb_ca_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)271 wusb_ca_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
272 {
273 	int			instance = ddi_get_instance(dip);
274 	char			*devinst;
275 	int			devinstlen;
276 	wusb_ca_state_t		*wusb_cap = NULL;
277 	int			status;
278 
279 	switch (cmd) {
280 	case DDI_ATTACH:
281 		break;
282 
283 	case DDI_RESUME:
284 		wusb_ca_cpr_resume(dip);
285 
286 		/*
287 		 * Always return success to work around enumeration failures.
288 		 * This works around an issue where devices which are present
289 		 * before a suspend and absent upon resume could cause a system
290 		 * panic on resume.
291 		 */
292 		return (DDI_SUCCESS);
293 	default:
294 		return (DDI_FAILURE);
295 	}
296 
297 	if (ddi_soft_state_zalloc(wusb_ca_statep, instance) == DDI_SUCCESS) {
298 		wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
299 	}
300 	if (wusb_cap == NULL)  {
301 
302 		return (DDI_FAILURE);
303 	}
304 
305 	wusb_cap->wusb_ca_dip = dip;
306 
307 	devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
308 	devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ",
309 	    ddi_driver_name(dip), instance);
310 
311 	wusb_cap->wusb_ca_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
312 	(void) strncpy(wusb_cap->wusb_ca_devinst, devinst, devinstlen);
313 	kmem_free(devinst, USB_MAXSTRINGLEN);
314 
315 	wusb_cap->wusb_ca_log_hdl = usb_alloc_log_hdl(dip, "wusb_ca",
316 	    &wusb_ca_errlevel, &wusb_ca_errmask, &wusb_ca_instance_debug, 0);
317 
318 	USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
319 	    "Attach: enter for attach");
320 
321 
322 
323 	if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) !=
324 	    USB_SUCCESS) {
325 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
326 		    "attach: usb_client_attach failed, error code:%d", status);
327 		goto fail;
328 	}
329 
330 	if ((status = usb_get_dev_data(dip, &wusb_cap->wusb_ca_reg,
331 	    USB_PARSE_LVL_ALL, 0)) != USB_SUCCESS) {
332 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
333 		    "attach: usb_get_dev_data failed, error code:%d", status);
334 		goto fail;
335 	}
336 
337 	usb_free_descr_tree(dip, wusb_cap->wusb_ca_reg);
338 
339 	mutex_init(&wusb_cap->wusb_ca_mutex, NULL, MUTEX_DRIVER,
340 	    wusb_cap->wusb_ca_reg->dev_iblock_cookie);
341 
342 	cv_init(&wusb_cap->wusb_ca_serial_cv, NULL, CV_DRIVER, NULL);
343 	wusb_cap->wusb_ca_serial_inuse = B_FALSE;
344 
345 	wusb_cap->wusb_ca_locks_initialized = B_TRUE;
346 
347 	/* create minor node */
348 	if (ddi_create_minor_node(dip, "wusb_ca", S_IFCHR, instance,
349 	    "wusb_ca", 0) != DDI_SUCCESS) {
350 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
351 		    "attach: Error creating minor node");
352 
353 		goto fail;
354 	}
355 
356 	/* Put online before PM init as can get power managed afterward. */
357 	wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
358 
359 	/* initialize power management */
360 	wusb_ca_init_power_mgmt(wusb_cap);
361 
362 	if (usb_register_hotplug_cbs(dip, wusb_ca_disconnect_callback,
363 	    wusb_ca_reconnect_callback) != USB_SUCCESS) {
364 
365 		goto fail;
366 	}
367 
368 	/* Report device */
369 	ddi_report_dev(dip);
370 
371 	return (DDI_SUCCESS);
372 
373 fail:
374 	if (wusb_cap) {
375 		(void) wusb_ca_cleanup(dip, wusb_cap);
376 	}
377 
378 	return (DDI_FAILURE);
379 }
380 
381 
382 /*
383  * wusb_ca_detach:
384  *	detach or suspend driver instance
385  *
386  * Note: in detach, only contention threads is from pm and disconnnect.
387  */
388 static int
wusb_ca_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)389 wusb_ca_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
390 {
391 	int		instance = ddi_get_instance(dip);
392 	int		rval = DDI_FAILURE;
393 	wusb_ca_state_t	*wusb_cap;
394 
395 	wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
396 	switch (cmd) {
397 	case DDI_DETACH:
398 		mutex_enter(&wusb_cap->wusb_ca_mutex);
399 		ASSERT((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) == 0);
400 		mutex_exit(&wusb_cap->wusb_ca_mutex);
401 
402 		USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
403 		    "Detach: enter for detach");
404 
405 		rval = wusb_ca_cleanup(dip, wusb_cap);
406 
407 		break;
408 	case DDI_SUSPEND:
409 		USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
410 		    "Detach: enter for suspend");
411 
412 		rval = wusb_ca_cpr_suspend(dip);
413 	default:
414 
415 		break;
416 	}
417 
418 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
419 }
420 
421 
422 /*
423  * wusb_ca_cleanup:
424  *	clean up the driver state for detach
425  */
426 static int
wusb_ca_cleanup(dev_info_t * dip,wusb_ca_state_t * wusb_cap)427 wusb_ca_cleanup(dev_info_t *dip, wusb_ca_state_t *wusb_cap)
428 {
429 	USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_cap->wusb_ca_log_hdl,
430 	    "Cleanup: enter");
431 
432 	if (wusb_cap->wusb_ca_locks_initialized) {
433 
434 		/* This must be done 1st to prevent more events from coming. */
435 		usb_unregister_hotplug_cbs(dip);
436 
437 		/*
438 		 * At this point, no new activity can be initiated. The driver
439 		 * has disabled hotplug callbacks. The Solaris framework has
440 		 * disabled new opens on a device being detached, and does not
441 		 * allow detaching an open device.
442 		 *
443 		 * The following ensures that all driver activity has drained.
444 		 */
445 		mutex_enter(&wusb_cap->wusb_ca_mutex);
446 		(void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
447 		wusb_ca_release_access(wusb_cap);
448 		mutex_exit(&wusb_cap->wusb_ca_mutex);
449 
450 		/* All device activity has died down. */
451 		wusb_ca_destroy_power_mgmt(wusb_cap);
452 
453 		/* start dismantling */
454 		ddi_remove_minor_node(dip, NULL);
455 
456 		cv_destroy(&wusb_cap->wusb_ca_serial_cv);
457 		mutex_destroy(&wusb_cap->wusb_ca_mutex);
458 	}
459 
460 	usb_client_detach(dip, wusb_cap->wusb_ca_reg);
461 
462 	usb_free_log_hdl(wusb_cap->wusb_ca_log_hdl);
463 
464 	if (wusb_cap->wusb_ca_devinst != NULL) {
465 		kmem_free(wusb_cap->wusb_ca_devinst,
466 		    strlen(wusb_cap->wusb_ca_devinst) + 1);
467 	}
468 
469 	ddi_soft_state_free(wusb_ca_statep, ddi_get_instance(dip));
470 	ddi_prop_remove_all(dip);
471 
472 	return (USB_SUCCESS);
473 }
474 
475 
476 /*ARGSUSED*/
477 static int
wusb_ca_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)478 wusb_ca_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
479 {
480 	wusb_ca_state_t	*wusb_cap =
481 	    ddi_get_soft_state(wusb_ca_statep, getminor(*devp));
482 	int rval = 0;
483 
484 	if (wusb_cap == NULL) {
485 
486 		return (ENXIO);
487 	}
488 
489 	USB_DPRINTF_L4(PRINT_MASK_OPEN, wusb_cap->wusb_ca_log_hdl,
490 	    "open: enter");
491 
492 	/*
493 	 * Keep it simple: one client at a time.
494 	 * Exclusive open only
495 	 */
496 	mutex_enter(&wusb_cap->wusb_ca_mutex);
497 	if ((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) != 0) {
498 		mutex_exit(&wusb_cap->wusb_ca_mutex);
499 
500 		return (EBUSY);
501 	}
502 	wusb_cap->wusb_ca_drv_state |= WUSB_CA_OPEN;
503 
504 	/*
505 	 * This is in place so that a disconnect or CPR doesn't interfere with
506 	 * pipe opens.
507 	 */
508 	if (wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_SIG) == 0) {
509 		wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
510 		mutex_exit(&wusb_cap->wusb_ca_mutex);
511 
512 		return (EINTR);
513 	}
514 
515 	mutex_exit(&wusb_cap->wusb_ca_mutex);
516 	if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
517 		USB_DPRINTF_L2(PRINT_MASK_OPEN, wusb_cap->wusb_ca_log_hdl,
518 		    "open: Error raising power");
519 		rval = EIO;
520 		goto done;
521 	}
522 	mutex_enter(&wusb_cap->wusb_ca_mutex);
523 
524 	/* Fail if device is no longer ready. */
525 	if (wusb_cap->wusb_ca_dev_state != USB_DEV_ONLINE) {
526 		mutex_exit(&wusb_cap->wusb_ca_mutex);
527 		rval = EIO;
528 		goto done;
529 	}
530 
531 	mutex_exit(&wusb_cap->wusb_ca_mutex);
532 
533 done:
534 	if (rval != 0) {
535 		mutex_enter(&wusb_cap->wusb_ca_mutex);
536 		wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
537 
538 		wusb_ca_release_access(wusb_cap);
539 		mutex_exit(&wusb_cap->wusb_ca_mutex);
540 
541 		wusb_ca_pm_idle_component(wusb_cap);
542 	} else {
543 
544 		/* Device is idle until it is used. */
545 		mutex_enter(&wusb_cap->wusb_ca_mutex);
546 		wusb_ca_release_access(wusb_cap);
547 		mutex_exit(&wusb_cap->wusb_ca_mutex);
548 	}
549 
550 	return (rval);
551 }
552 
553 
554 /*ARGSUSED*/
555 static int
wusb_ca_close(dev_t dev,int flag,int otyp,cred_t * cred_p)556 wusb_ca_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
557 {
558 	wusb_ca_state_t	*wusb_cap =
559 	    ddi_get_soft_state(wusb_ca_statep, getminor(dev));
560 
561 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, wusb_cap->wusb_ca_log_hdl,
562 	    "close: enter");
563 
564 	mutex_enter(&wusb_cap->wusb_ca_mutex);
565 	(void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
566 	mutex_exit(&wusb_cap->wusb_ca_mutex);
567 
568 	/* Perform device session cleanup here. */
569 
570 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, wusb_cap->wusb_ca_log_hdl,
571 	    "close: cleaning up...");
572 
573 	/*
574 	 * USBA automatically flushes/resets active non-default pipes
575 	 * when they are closed.  We can't reset default pipe, but we
576 	 * can wait for all requests on it from this dip to drain.
577 	 */
578 	(void) usb_pipe_drain_reqs(wusb_cap->wusb_ca_dip,
579 	    wusb_cap->wusb_ca_reg->dev_default_ph, 0,
580 	    USB_FLAGS_SLEEP, NULL, 0);
581 
582 	mutex_enter(&wusb_cap->wusb_ca_mutex);
583 
584 	wusb_cap->wusb_ca_drv_state &= ~WUSB_CA_OPEN;
585 
586 	wusb_ca_release_access(wusb_cap);
587 	mutex_exit(&wusb_cap->wusb_ca_mutex);
588 
589 	wusb_ca_pm_idle_component(wusb_cap);
590 
591 	return (0);
592 }
593 
594 
595 /*
596  * ioctl for cable association operations.
597  */
598 /*ARGSUSED*/
599 static int
wusb_ca_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)600 wusb_ca_ioctl(dev_t dev, int cmd, intptr_t arg,
601 		int mode, cred_t *cred_p, int *rval_p)
602 {
603 	wusb_ca_state_t	*wusb_cap =
604 	    ddi_get_soft_state(wusb_ca_statep, getminor(dev));
605 
606 	USB_DPRINTF_L4(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
607 	    "ioctl enter");
608 
609 	mutex_enter(&wusb_cap->wusb_ca_mutex);
610 
611 	switch (cmd) {
612 	case CBAF_IOCTL_GET_ASSO_INFO:
613 		*rval_p = wusb_cbaf_get_asso_info(wusb_cap, arg, mode);
614 
615 		break;
616 	case CBAF_IOCTL_GET_ASSO_REQS:
617 		*rval_p = wusb_cbaf_get_asso_reqs(wusb_cap, arg, mode);
618 
619 		break;
620 	case CBAF_IOCTL_SET_HOST_INFO:
621 		*rval_p = wusb_cbaf_set_host_info(wusb_cap, arg, mode);
622 
623 		break;
624 	case CBAF_IOCTL_GET_DEVICE_INFO:
625 		*rval_p = wusb_cbaf_get_device_info(wusb_cap, arg, mode);
626 
627 		break;
628 	case CBAF_IOCTL_SET_CONNECTION:
629 		*rval_p = wusb_cbaf_set_connection(wusb_cap, arg, mode);
630 
631 		break;
632 	case CBAF_IOCTL_SET_FAILURE:
633 		*rval_p = wusb_cbaf_set_failure(wusb_cap, arg, mode);
634 
635 		break;
636 	default:
637 
638 		*rval_p = EINVAL;
639 	}
640 
641 	mutex_exit(&wusb_cap->wusb_ca_mutex);
642 
643 	return (*rval_p);
644 }
645 
646 
647 /*
648  * wusb_ca_disconnect_callback:
649  *	Called when device hotplug-removed.
650  *		Close pipes. (This does not attempt to contact device.)
651  *		Set state to DISCONNECTED
652  */
653 static int
wusb_ca_disconnect_callback(dev_info_t * dip)654 wusb_ca_disconnect_callback(dev_info_t *dip)
655 {
656 	int instance = ddi_get_instance(dip);
657 	wusb_ca_state_t	*wusb_cap;
658 
659 	wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
660 
661 	USB_DPRINTF_L4(PRINT_MASK_CB, wusb_cap->wusb_ca_log_hdl,
662 	    "disconnect: enter");
663 
664 	mutex_enter(&wusb_cap->wusb_ca_mutex);
665 	(void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
666 
667 	/*
668 	 * Save any state of device or IO in progress required by
669 	 * wusb_ca_restore_device_state for proper device "thawing" later.
670 	 */
671 	wusb_cap->wusb_ca_dev_state = USB_DEV_DISCONNECTED;
672 
673 	wusb_ca_release_access(wusb_cap);
674 	mutex_exit(&wusb_cap->wusb_ca_mutex);
675 
676 	return (USB_SUCCESS);
677 }
678 
679 
680 /*
681  * wusb_ca_reconnect_callback:
682  *	Called with device hotplug-inserted
683  *		Restore state
684  */
685 static int
wusb_ca_reconnect_callback(dev_info_t * dip)686 wusb_ca_reconnect_callback(dev_info_t *dip)
687 {
688 	int instance = ddi_get_instance(dip);
689 	wusb_ca_state_t	*wusb_cap;
690 
691 	wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
692 
693 	USB_DPRINTF_L4(PRINT_MASK_CB, wusb_cap->wusb_ca_log_hdl,
694 	    "reconnect: enter");
695 
696 	mutex_enter(&wusb_cap->wusb_ca_mutex);
697 	(void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
698 	wusb_ca_restore_device_state(dip, wusb_cap);
699 	wusb_ca_release_access(wusb_cap);
700 	mutex_exit(&wusb_cap->wusb_ca_mutex);
701 
702 	return (USB_SUCCESS);
703 }
704 
705 
706 /*
707  * wusb_ca_restore_device_state:
708  *	Called during hotplug-reconnect and resume.
709  *		reenable power management
710  *		Verify the device is the same as before the disconnect/suspend.
711  *		Restore device state
712  *		Thaw any IO which was frozen.
713  *		Quiesce device.  (Other routines will activate if thawed IO.)
714  *		Set device online.
715  *		Leave device disconnected if there are problems.
716  */
717 static void
wusb_ca_restore_device_state(dev_info_t * dip,wusb_ca_state_t * wusb_cap)718 wusb_ca_restore_device_state(dev_info_t *dip, wusb_ca_state_t *wusb_cap)
719 {
720 	USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
721 	    "wusb_ca_restore_device_state: enter");
722 
723 	ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
724 
725 	ASSERT((wusb_cap->wusb_ca_dev_state == USB_DEV_DISCONNECTED) ||
726 	    (wusb_cap->wusb_ca_dev_state == USB_DEV_SUSPENDED));
727 
728 	mutex_exit(&wusb_cap->wusb_ca_mutex);
729 
730 	if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
731 		USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
732 		    "wusb_ca_restore_device_state: Error raising power");
733 
734 		goto fail;
735 	}
736 
737 	/* Check if we are talking to the same device */
738 	if (wusb_ca_check_same_device(wusb_cap) != USB_SUCCESS) {
739 		wusb_ca_pm_idle_component(wusb_cap);
740 
741 		goto fail;
742 	}
743 
744 	mutex_enter(&wusb_cap->wusb_ca_mutex);
745 	wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
746 
747 	if ((wusb_cap->wusb_ca_pm) &&
748 	    (wusb_cap->wusb_ca_pm->wusb_ca_remote_wakeup)) {
749 		mutex_exit(&wusb_cap->wusb_ca_mutex);
750 
751 		/* Failure here means device disappeared again. */
752 		if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) !=
753 		    USB_SUCCESS) {
754 			USB_DPRINTF_L2(PRINT_MASK_CPR,
755 			    wusb_cap->wusb_ca_log_hdl,
756 			    "device may or may not be accessible. "
757 			    "Please verify reconnection");
758 		}
759 
760 		mutex_enter(&wusb_cap->wusb_ca_mutex);
761 	}
762 
763 	mutex_exit(&wusb_cap->wusb_ca_mutex);
764 	wusb_ca_pm_idle_component(wusb_cap);
765 	mutex_enter(&wusb_cap->wusb_ca_mutex);
766 
767 	USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
768 	    "wusb_ca_restore_device_state: end");
769 
770 	return;
771 
772 fail:
773 	/* change the device state from suspended to disconnected */
774 	mutex_enter(&wusb_cap->wusb_ca_mutex);
775 	wusb_cap->wusb_ca_dev_state = USB_DEV_DISCONNECTED;
776 }
777 
778 
779 /*
780  * wusb_ca_cpr_suspend:
781  *	Clean up device.
782  *	Wait for any IO to finish, then close pipes.
783  *	Quiesce device.
784  */
785 static int
wusb_ca_cpr_suspend(dev_info_t * dip)786 wusb_ca_cpr_suspend(dev_info_t *dip)
787 {
788 	int		instance = ddi_get_instance(dip);
789 	wusb_ca_state_t	*wusb_cap;
790 
791 	wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
792 
793 	USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
794 	    "suspend enter");
795 
796 	/* Serialize to prevent races with detach, open, device access. */
797 	mutex_enter(&wusb_cap->wusb_ca_mutex);
798 	(void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
799 	mutex_exit(&wusb_cap->wusb_ca_mutex);
800 
801 	if (wusb_ca_pm_busy_component(wusb_cap) != DDI_SUCCESS) {
802 		USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
803 		    "suspend: Error raising power");
804 		wusb_ca_pm_idle_component(wusb_cap);
805 
806 		return (USB_FAILURE);
807 	}
808 
809 	mutex_enter(&wusb_cap->wusb_ca_mutex);
810 
811 	/*
812 	 * Set dev_state to suspended so other driver threads don't start any
813 	 * new I/O.
814 	 */
815 
816 	/* Don't suspend if the device is open. */
817 	if ((wusb_cap->wusb_ca_drv_state & WUSB_CA_OPEN) != 0) {
818 		USB_DPRINTF_L2(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
819 		    "suspend: Device is open.  Can't suspend");
820 
821 		wusb_ca_release_access(wusb_cap);
822 		mutex_exit(&wusb_cap->wusb_ca_mutex);
823 
824 		wusb_ca_pm_idle_component(wusb_cap);
825 
826 		return (USB_FAILURE);
827 	}
828 
829 	wusb_cap->wusb_ca_dev_state = USB_DEV_SUSPENDED;
830 
831 	wusb_ca_release_access(wusb_cap);
832 	mutex_exit(&wusb_cap->wusb_ca_mutex);
833 
834 	wusb_ca_pm_idle_component(wusb_cap);
835 
836 	USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
837 	    "suspend: success");
838 
839 	return (USB_SUCCESS);
840 }
841 
842 
843 /*
844  * wusb_ca_cpr_resume:
845  *
846  *	wusb_ca_restore_device_state marks success by putting device back online
847  */
848 static void
wusb_ca_cpr_resume(dev_info_t * dip)849 wusb_ca_cpr_resume(dev_info_t *dip)
850 {
851 	int		instance = ddi_get_instance(dip);
852 	wusb_ca_state_t	*wusb_cap;
853 
854 	wusb_cap = ddi_get_soft_state(wusb_ca_statep, instance);
855 
856 	USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_cap->wusb_ca_log_hdl,
857 	    "resume: enter");
858 
859 	/*
860 	 * A pm_raise_power in wusb_ca_restore_device_state will bring
861 	 * the power-up state of device into synch with the system.
862 	 */
863 	mutex_enter(&wusb_cap->wusb_ca_mutex);
864 	wusb_ca_restore_device_state(dip, wusb_cap);
865 	mutex_exit(&wusb_cap->wusb_ca_mutex);
866 }
867 
868 
869 static int
wusb_ca_pm_busy_component(wusb_ca_state_t * wusb_cap)870 wusb_ca_pm_busy_component(wusb_ca_state_t *wusb_cap)
871 {
872 	int rval = DDI_SUCCESS;
873 
874 	mutex_enter(&wusb_cap->wusb_ca_mutex);
875 	if (wusb_cap->wusb_ca_pm != NULL) {
876 		wusb_cap->wusb_ca_pm->wusb_ca_pm_busy++;
877 		mutex_exit(&wusb_cap->wusb_ca_mutex);
878 		if (pm_busy_component(wusb_cap->wusb_ca_dip, 0) ==
879 		    DDI_SUCCESS) {
880 			(void) pm_raise_power(
881 			    wusb_cap->wusb_ca_dip, 0, USB_DEV_OS_FULL_PWR);
882 			mutex_enter(&wusb_cap->wusb_ca_mutex);
883 		} else {
884 			mutex_enter(&wusb_cap->wusb_ca_mutex);
885 			wusb_cap->wusb_ca_pm->wusb_ca_pm_busy--;
886 		}
887 	}
888 	mutex_exit(&wusb_cap->wusb_ca_mutex);
889 
890 	return (rval);
891 }
892 
893 static void
wusb_ca_pm_idle_component(wusb_ca_state_t * wusb_cap)894 wusb_ca_pm_idle_component(wusb_ca_state_t *wusb_cap)
895 {
896 	mutex_enter(&wusb_cap->wusb_ca_mutex);
897 	if (wusb_cap->wusb_ca_pm != NULL) {
898 		mutex_exit(&wusb_cap->wusb_ca_mutex);
899 		if (pm_idle_component(wusb_cap->wusb_ca_dip, 0) ==
900 		    DDI_SUCCESS) {
901 			mutex_enter(&wusb_cap->wusb_ca_mutex);
902 			ASSERT(wusb_cap->wusb_ca_pm->wusb_ca_pm_busy > 0);
903 			wusb_cap->wusb_ca_pm->wusb_ca_pm_busy--;
904 			mutex_exit(&wusb_cap->wusb_ca_mutex);
905 		}
906 		mutex_enter(&wusb_cap->wusb_ca_mutex);
907 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
908 		    "wusb_ca_pm_idle_component: %d",
909 		    wusb_cap->wusb_ca_pm->wusb_ca_pm_busy);
910 	}
911 	mutex_exit(&wusb_cap->wusb_ca_mutex);
912 }
913 
914 /*
915  * wusb_ca_power :
916  *	Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
917  *	usb_req_raise_power and usb_req_lower_power.
918  */
919 /* ARGSUSED */
920 static int
wusb_ca_power(dev_info_t * dip,int comp,int level)921 wusb_ca_power(dev_info_t *dip, int comp, int level)
922 {
923 	wusb_ca_state_t	*wusb_cap;
924 	wusb_ca_power_t	*pm;
925 	int	rval = USB_SUCCESS;
926 
927 	wusb_cap = ddi_get_soft_state(wusb_ca_statep, ddi_get_instance(dip));
928 
929 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
930 	    "wusb_ca_power: enter: level = %d", level);
931 
932 	mutex_enter(&wusb_cap->wusb_ca_mutex);
933 	(void) wusb_ca_serialize_access(wusb_cap, WUSB_CA_SER_NOSIG);
934 
935 	/*
936 	 * If we are disconnected/suspended, return success. Note that if we
937 	 * return failure, bringing down the system will hang when PM tries
938 	 * to power up all devices
939 	 */
940 	if ((wusb_cap->wusb_ca_dev_state == USB_DEV_DISCONNECTED) ||
941 	    (wusb_cap->wusb_ca_dev_state == USB_DEV_SUSPENDED)) {
942 
943 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
944 		    "wusb_ca_power: disconnected/suspended "
945 		    "dev_state=%d", wusb_cap->wusb_ca_dev_state);
946 		rval = USB_SUCCESS;
947 
948 		goto done;
949 	}
950 
951 	if (wusb_cap->wusb_ca_pm == NULL) {
952 
953 		goto done;
954 	}
955 
956 	pm = wusb_cap->wusb_ca_pm;
957 
958 	/* Check if we are transitioning to a legal power level */
959 	if (USB_DEV_PWRSTATE_OK(pm->wusb_ca_pwr_states, level)) {
960 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
961 		    "wusb_ca_power: illegal power level = %d "
962 		    "pwr_states: %x", level, pm->wusb_ca_pwr_states);
963 
964 		goto done;
965 	}
966 
967 	switch (level) {
968 	case USB_DEV_OS_PWR_OFF :
969 		/* fail attempt to go to low power if busy */
970 		if (pm->wusb_ca_pm_busy) {
971 
972 			goto done;
973 		}
974 		if (wusb_cap->wusb_ca_dev_state == USB_DEV_ONLINE) {
975 			(void) usb_set_device_pwrlvl3(wusb_cap->wusb_ca_dip);
976 
977 			wusb_cap->wusb_ca_dev_state = USB_DEV_PWRED_DOWN;
978 			wusb_cap->wusb_ca_pm->wusb_ca_current_power =
979 			    USB_DEV_OS_PWR_OFF;
980 		}
981 
982 		break;
983 
984 	case USB_DEV_OS_FULL_PWR :
985 		/*
986 		 * PM framework tries to put us in full power during system
987 		 * shutdown. Handle USB_DEV_PWRED_DOWN only.
988 		 */
989 		if (wusb_cap->wusb_ca_dev_state == USB_DEV_PWRED_DOWN) {
990 			(void) usb_set_device_pwrlvl0(wusb_cap->wusb_ca_dip);
991 			wusb_cap->wusb_ca_dev_state = USB_DEV_ONLINE;
992 			wusb_cap->wusb_ca_pm->wusb_ca_current_power =
993 			    USB_DEV_OS_FULL_PWR;
994 		}
995 
996 		break;
997 
998 	/* Levels 1 and 2 are not supported by this driver to keep it simple. */
999 	default:
1000 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1001 		    "wusb_ca_power: power level %d not supported", level);
1002 		break;
1003 	}
1004 done:
1005 	wusb_ca_release_access(wusb_cap);
1006 	mutex_exit(&wusb_cap->wusb_ca_mutex);
1007 
1008 	/* Generally return success to make PM succeed */
1009 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1010 }
1011 
1012 
1013 /*
1014  * wusb_ca_init_power_mgmt:
1015  *	Initialize power management and remote wakeup functionality.
1016  *	No mutex is necessary in this function as it's called only by attach.
1017  */
1018 static void
wusb_ca_init_power_mgmt(wusb_ca_state_t * wusb_cap)1019 wusb_ca_init_power_mgmt(wusb_ca_state_t *wusb_cap)
1020 {
1021 	wusb_ca_power_t *wusb_capm;
1022 	uint_t		pwr_states;
1023 
1024 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1025 	    "init_power_mgmt enter");
1026 
1027 	/* Allocate the state structure */
1028 	wusb_capm = kmem_zalloc(sizeof (wusb_ca_power_t), KM_SLEEP);
1029 	wusb_cap->wusb_ca_pm = wusb_capm;
1030 	wusb_capm->wusb_ca_state = wusb_cap;
1031 	wusb_capm->wusb_ca_pm_capabilities = 0;
1032 	wusb_capm->wusb_ca_current_power = USB_DEV_OS_FULL_PWR;
1033 
1034 	if (usb_create_pm_components(wusb_cap->wusb_ca_dip,
1035 	    &pwr_states) == USB_SUCCESS) {
1036 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1037 		    "wusb_ca_init_power_mgmt: created PM components");
1038 
1039 		wusb_capm->wusb_ca_pwr_states = (uint8_t)pwr_states;
1040 		(void) pm_raise_power(wusb_cap->wusb_ca_dip, 0,
1041 		    USB_DEV_OS_FULL_PWR);
1042 	} else {
1043 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1044 		    "wusb_ca_init_power_mgmt: create_pm_compts failed");
1045 	}
1046 
1047 	/*
1048 	 * If remote wakeup is not available you may not want to do
1049 	 * power management.
1050 	 */
1051 	if (usb_handle_remote_wakeup(wusb_cap->wusb_ca_dip,
1052 	    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
1053 		wusb_capm->wusb_ca_remote_wakeup = 1;
1054 	} else {
1055 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1056 		    "wusb_ca_init_power_mgmt: failure enabling remote wakeup");
1057 	}
1058 
1059 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1060 	    "wusb_ca_init_power_mgmt: end");
1061 }
1062 
1063 
1064 /*
1065  * wusb_ca_destroy_power_mgmt:
1066  *	Shut down and destroy power management and remote wakeup functionality.
1067  */
1068 static void
wusb_ca_destroy_power_mgmt(wusb_ca_state_t * wusb_cap)1069 wusb_ca_destroy_power_mgmt(wusb_ca_state_t *wusb_cap)
1070 {
1071 	wusb_ca_power_t *wusb_capm;
1072 
1073 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_cap->wusb_ca_log_hdl,
1074 	    "destroy_power_mgmt enter");
1075 
1076 	ASSERT(!mutex_owned(&wusb_cap->wusb_ca_mutex));
1077 
1078 	mutex_enter(&wusb_cap->wusb_ca_mutex);
1079 
1080 	wusb_capm = wusb_cap->wusb_ca_pm;
1081 	if (!wusb_capm) {
1082 		mutex_exit(&wusb_cap->wusb_ca_mutex);
1083 
1084 		return;
1085 	}
1086 
1087 	mutex_exit(&wusb_cap->wusb_ca_mutex);
1088 
1089 	(void) wusb_ca_pm_busy_component(wusb_cap);
1090 
1091 	mutex_enter(&wusb_cap->wusb_ca_mutex);
1092 	if (wusb_cap->wusb_ca_dev_state != USB_DEV_DISCONNECTED) {
1093 		int rval;
1094 
1095 		if (wusb_capm->wusb_ca_remote_wakeup) {
1096 			mutex_exit(&wusb_cap->wusb_ca_mutex);
1097 
1098 			(void) pm_raise_power(wusb_cap->wusb_ca_dip, 0,
1099 			    USB_DEV_OS_FULL_PWR);
1100 
1101 			rval = usb_handle_remote_wakeup(
1102 			    wusb_cap->wusb_ca_dip,
1103 			    USB_REMOTE_WAKEUP_DISABLE);
1104 
1105 			USB_DPRINTF_L2(PRINT_MASK_PM,
1106 			    wusb_cap->wusb_ca_log_hdl,
1107 			    "wusb_ca_destroy_power_mgmt: "
1108 			    "Error disabling rmt wakeup: rval = %d",
1109 			    rval);
1110 
1111 			mutex_enter(&wusb_cap->wusb_ca_mutex);
1112 		}
1113 	}
1114 
1115 	mutex_exit(&wusb_cap->wusb_ca_mutex);
1116 
1117 	/*
1118 	 * Since remote wakeup is disabled now,
1119 	 * no one can raise power
1120 	 * and get to device once power is lowered here.
1121 	 */
1122 	(void) pm_lower_power(wusb_cap->wusb_ca_dip, 0, USB_DEV_OS_PWR_OFF);
1123 	wusb_ca_pm_idle_component(wusb_cap);
1124 
1125 	mutex_enter(&wusb_cap->wusb_ca_mutex);
1126 	kmem_free(wusb_cap->wusb_ca_pm, sizeof (wusb_ca_power_t));
1127 	wusb_cap->wusb_ca_pm = NULL;
1128 	mutex_exit(&wusb_cap->wusb_ca_mutex);
1129 }
1130 
1131 
1132 /*
1133  * wusb_ca_serialize_access:
1134  *    Get the serial synchronization object before returning.
1135  *
1136  * Arguments:
1137  *    wusb_cap - Pointer to wusb_ca state structure
1138  *    waitsig - Set to:
1139  *	WUSB_CA_SER_SIG - to wait such that a signal can interrupt
1140  *	WUSB_CA_SER_NOSIG - to wait such that a signal cannot interrupt
1141  */
1142 static int
wusb_ca_serialize_access(wusb_ca_state_t * wusb_cap,boolean_t waitsig)1143 wusb_ca_serialize_access(wusb_ca_state_t *wusb_cap, boolean_t waitsig)
1144 {
1145 	int rval = 1;
1146 
1147 	ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
1148 
1149 	while (wusb_cap->wusb_ca_serial_inuse) {
1150 		if (waitsig == WUSB_CA_SER_SIG) {
1151 			rval = cv_wait_sig(&wusb_cap->wusb_ca_serial_cv,
1152 			    &wusb_cap->wusb_ca_mutex);
1153 		} else {
1154 			cv_wait(&wusb_cap->wusb_ca_serial_cv,
1155 			    &wusb_cap->wusb_ca_mutex);
1156 		}
1157 	}
1158 	wusb_cap->wusb_ca_serial_inuse = B_TRUE;
1159 
1160 	return (rval);
1161 }
1162 
1163 
1164 /*
1165  * wusb_ca_release_access:
1166  *    Release the serial synchronization object.
1167  */
1168 static void
wusb_ca_release_access(wusb_ca_state_t * wusb_cap)1169 wusb_ca_release_access(wusb_ca_state_t *wusb_cap)
1170 {
1171 	ASSERT(mutex_owned(&wusb_cap->wusb_ca_mutex));
1172 	wusb_cap->wusb_ca_serial_inuse = B_FALSE;
1173 	cv_broadcast(&wusb_cap->wusb_ca_serial_cv);
1174 }
1175 
1176 
1177 /*
1178  * wusb_ca_check_same_device:
1179  *	Check if the device connected to the port is the same as
1180  *	the previous device that was in the port.  The previous device is
1181  *	represented by the dip on record for the port.	Print a message
1182  *	if the device is different.  Can block.
1183  *
1184  * return values:
1185  *	USB_SUCCESS:		same device
1186  *	USB_INVALID_VERSION	not same device
1187  *	USB_FAILURE:		Failure processing request
1188  */
1189 static int
wusb_ca_check_same_device(wusb_ca_state_t * wusb_cap)1190 wusb_ca_check_same_device(wusb_ca_state_t *wusb_cap)
1191 {
1192 	usb_dev_descr_t		*orig_usb_dev_descr;
1193 	usb_dev_descr_t		usb_dev_descr;
1194 	mblk_t			*pdata = NULL;
1195 	int			rval;
1196 	char			*buf;
1197 	usb_cr_t		completion_reason;
1198 	usb_cb_flags_t		cb_flags;
1199 	boolean_t		match = B_TRUE;
1200 
1201 	usb_ctrl_setup_t	setup = {
1202 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD |
1203 		USB_DEV_REQ_RCPT_DEV,
1204 	    USB_REQ_GET_DESCR,		/* bRequest */
1205 	    USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
1206 	    0,				/* wIndex */
1207 	    USB_DEV_DESCR_SIZE,		/* wLength */
1208 	    0				/* request attributes */
1209 	};
1210 
1211 	ASSERT(!mutex_owned(&wusb_cap->wusb_ca_mutex));
1212 
1213 	orig_usb_dev_descr = wusb_cap->wusb_ca_reg->dev_descr;
1214 
1215 	/* get the "new" device descriptor */
1216 	rval = usb_pipe_ctrl_xfer_wait(wusb_cap->wusb_ca_reg->dev_default_ph,
1217 	    &setup, &pdata, &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1218 
1219 	if (rval != USB_SUCCESS) {
1220 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1221 		    "wusb_ca_check_same_device: "
1222 		    "getting device descriptor failed "
1223 		    "rval=%d, cr=%d, cb=0x%x\n",
1224 		    rval, completion_reason, cb_flags);
1225 		freemsg(pdata);
1226 
1227 		return (USB_FAILURE);
1228 	}
1229 
1230 	ASSERT(pdata != NULL);
1231 
1232 	(void) usb_parse_data("2cs4c3s4c", pdata->b_rptr,
1233 	    (intptr_t)pdata->b_wptr - (intptr_t)pdata->b_rptr, &usb_dev_descr,
1234 	    sizeof (usb_dev_descr_t));
1235 
1236 	freemsg(pdata);
1237 	pdata = NULL;
1238 
1239 	/* Always check the device descriptor length. */
1240 	if (usb_dev_descr.bLength != USB_DEV_DESCR_SIZE) {
1241 		match = B_FALSE;
1242 
1243 	/* Always check the device descriptor. */
1244 	} else if (bcmp(orig_usb_dev_descr,
1245 	    (char *)&usb_dev_descr, USB_DEV_DESCR_SIZE) != 0) {
1246 		match = B_FALSE;
1247 	}
1248 
1249 	/* if requested & this device has a serial number check and compare */
1250 	if ((match == B_TRUE) &&
1251 	    (wusb_cap->wusb_ca_reg->dev_serial != NULL)) {
1252 		buf = kmem_alloc(USB_MAXSTRINGLEN, KM_SLEEP);
1253 		if (usb_get_string_descr(wusb_cap->wusb_ca_dip, USB_LANG_ID,
1254 		    usb_dev_descr.iSerialNumber, buf,
1255 		    USB_MAXSTRINGLEN) == USB_SUCCESS) {
1256 			match =
1257 			    (strcmp(buf,
1258 			    wusb_cap->wusb_ca_reg->dev_serial) == 0);
1259 		}
1260 		kmem_free(buf, USB_MAXSTRINGLEN);
1261 	}
1262 
1263 	if (match == B_FALSE) {
1264 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1265 		    "Device is not identical to the "
1266 		    "previous one this port.\n"
1267 		    "Please disconnect and reconnect");
1268 
1269 		return (USB_INVALID_VERSION);
1270 	}
1271 
1272 	return (USB_SUCCESS);
1273 }
1274 
1275 
1276 /* get association info */
1277 int
wusb_cbaf_get_asso_info(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1278 wusb_cbaf_get_asso_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1279 {
1280 	usb_pipe_handle_t	pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1281 	usb_ctrl_setup_t	setup;
1282 	usb_cr_t		completion_reason;
1283 	usb_cb_flags_t		cb_flags;
1284 	wusb_cbaf_asso_info_t	ca_info;
1285 	mblk_t			*pdata = NULL;
1286 	int rval;
1287 
1288 	setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1289 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1290 	setup.bRequest =  WUSB_CBAF_GET_ASSOCIATION_INFORMATION;
1291 	setup.wValue = 0;
1292 	setup.wIndex = 0;
1293 	setup.wLength = WUSB_ASSO_INFO_SIZE;
1294 	setup.attrs = USB_ATTRS_NONE;
1295 
1296 	rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1297 	    &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1298 
1299 	if (rval != USB_SUCCESS) {
1300 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1301 		"cr = %d cb_flags = %d", completion_reason, cb_flags);
1302 
1303 		return (EIO);
1304 	}
1305 	if (pdata == NULL || msgsize(pdata) == 0) {
1306 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1307 		    "empty pdata");
1308 
1309 		return (EIO);
1310 	}
1311 
1312 	rval = usb_parse_data("scs", pdata->b_rptr, WUSB_ASSO_INFO_SIZE,
1313 	    &ca_info, sizeof (ca_info));
1314 	if (rval <= 0) {
1315 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1316 		    "parse data");
1317 
1318 		return (EIO);
1319 	}
1320 
1321 	rval = ddi_copyout(&ca_info, (void *)arg, sizeof (ca_info), flag);
1322 	if (rval != 0) {
1323 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1324 		    "ddi_copyout");
1325 
1326 		return (EIO);
1327 	}
1328 
1329 	freemsg(pdata);
1330 
1331 	return (0);
1332 }
1333 
1334 /* get request array */
1335 int
wusb_cbaf_get_asso_reqs(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1336 wusb_cbaf_get_asso_reqs(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1337 {
1338 	usb_pipe_handle_t	pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1339 	usb_ctrl_setup_t	setup;
1340 	usb_cr_t		completion_reason;
1341 	usb_cb_flags_t		cb_flags;
1342 	wusb_cbaf_asso_info_t	ca_info;
1343 	wusb_cbaf_asso_req_t	*ca_reqs;
1344 	mblk_t			*pdata = NULL;
1345 	uchar_t			*data;
1346 	int rval, reqs_size, i;
1347 
1348 	rval = ddi_copyin((void *)arg, &ca_info, sizeof (ca_info), flag);
1349 	if (rval != 0) {
1350 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1351 		    "ddi_copyin");
1352 
1353 		return (EIO);
1354 	}
1355 
1356 	setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1357 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1358 	setup.bRequest =  WUSB_CBAF_GET_ASSOCIATION_INFORMATION;
1359 	setup.wValue = 0;
1360 	setup.wIndex = 0;
1361 	setup.wLength = ca_info.Length;
1362 	setup.attrs = USB_ATTRS_NONE;
1363 
1364 	rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1365 	    &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1366 
1367 	if (rval != USB_SUCCESS) {
1368 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1369 		"cr = %d cb_flags = %d", completion_reason, cb_flags);
1370 
1371 		return (EIO);
1372 	}
1373 	if (pdata == NULL || msgsize(pdata) == 0) {
1374 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1375 		    "empty pdata");
1376 
1377 		return (EIO);
1378 	}
1379 
1380 	reqs_size = sizeof (wusb_cbaf_asso_req_t) *
1381 	    ca_info.NumAssociationRequests;
1382 	ca_reqs = (wusb_cbaf_asso_req_t	*)kmem_zalloc(reqs_size, KM_SLEEP);
1383 
1384 	data = pdata->b_rptr + WUSB_ASSO_INFO_SIZE;
1385 	for (i = 0; i < ca_info.NumAssociationRequests; i++) {
1386 		rval = usb_parse_data("ccssl", data, WUSB_ASSO_REQUEST_SIZE,
1387 		    &(ca_reqs[i]), sizeof (wusb_cbaf_asso_req_t));
1388 		if (rval <= 0) {
1389 			USB_DPRINTF_L2(PRINT_MASK_ALL,
1390 			    wusb_cap->wusb_ca_log_hdl,
1391 			    "parse data");
1392 
1393 			return (EIO);
1394 		}
1395 		data += WUSB_ASSO_REQUEST_SIZE;
1396 	}
1397 
1398 	rval = ddi_copyout(ca_reqs, (void *)(arg + sizeof (ca_info)),
1399 	    reqs_size, flag);
1400 	if (rval != 0) {
1401 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1402 		    "ddi_copyout");
1403 
1404 		return (EIO);
1405 	}
1406 
1407 	freemsg(pdata);
1408 	kmem_free(ca_reqs, reqs_size);
1409 
1410 	return (0);
1411 }
1412 
1413 /* set host info */
1414 int
wusb_cbaf_set_host_info(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1415 wusb_cbaf_set_host_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1416 {
1417 	usb_pipe_handle_t	pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1418 	usb_ctrl_setup_t	setup;
1419 	usb_cr_t		completion_reason;
1420 	usb_cb_flags_t		cb_flags;
1421 	wusb_cbaf_host_info_t	host_info;
1422 	mblk_t			*pdata;
1423 	int rval;
1424 
1425 	rval = ddi_copyin((void *)arg, &host_info, sizeof (host_info), flag);
1426 	if (rval != 0) {
1427 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1428 		    "ddi_copyin");
1429 
1430 		return (EIO);
1431 	}
1432 
1433 	if ((pdata = trans_from_host_info(&host_info)) == NULL) {
1434 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1435 		    "trans host info");
1436 
1437 		return (EIO);
1438 	}
1439 
1440 	setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1441 	setup.bRequest =  WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1442 	setup.wValue = 0x101;
1443 	setup.wIndex = 0;
1444 	setup.wLength = WUSB_HOST_INFO_SIZE;
1445 	setup.attrs = USB_ATTRS_NONE;
1446 
1447 	rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1448 	    &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1449 
1450 	freemsg(pdata);
1451 
1452 	if (rval != USB_SUCCESS) {
1453 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1454 		"cr = %d cb_flags = 0x%03x", completion_reason, cb_flags);
1455 
1456 		return (EIO);
1457 	}
1458 
1459 	return (0);
1460 }
1461 
1462 /* get device info */
1463 int
wusb_cbaf_get_device_info(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1464 wusb_cbaf_get_device_info(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1465 {
1466 	usb_pipe_handle_t	pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1467 	usb_ctrl_setup_t	setup;
1468 	usb_cr_t		completion_reason;
1469 	usb_cb_flags_t		cb_flags;
1470 	wusb_cbaf_device_info_t	device_info;
1471 	mblk_t			*pdata = NULL;
1472 	int rval;
1473 
1474 	setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
1475 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1476 	setup.bRequest =  WUSB_CBAF_GET_ASSOCIATION_REQUEST;
1477 	setup.wValue = 0x200;
1478 	setup.wIndex = 0;
1479 	setup.wLength = WUSB_DEVICE_INFO_SIZE;
1480 	setup.attrs = USB_ATTRS_NONE;
1481 
1482 	rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1483 	    &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1484 
1485 	if (rval != USB_SUCCESS) {
1486 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1487 		    "cr = %d cb_flags = %d", completion_reason, cb_flags);
1488 
1489 		return (EIO);
1490 	}
1491 	if (pdata == NULL || msgsize(pdata) == 0) {
1492 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1493 		    "empty pdata");
1494 
1495 		return (EIO);
1496 	}
1497 
1498 	if (trans_to_device_info(wusb_cap, pdata, &device_info) != 0) {
1499 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1500 		    "trans to device_info");
1501 
1502 		return (EIO);
1503 	}
1504 
1505 	rval = ddi_copyout(&device_info, (void *)arg,
1506 	    sizeof (device_info), flag);
1507 	if (rval != 0) {
1508 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1509 		    "ddi_copyout");
1510 
1511 		return (EIO);
1512 	}
1513 
1514 	freemsg(pdata);
1515 
1516 	return (0);
1517 }
1518 
1519 /* set connection to device */
1520 int
wusb_cbaf_set_connection(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1521 wusb_cbaf_set_connection(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1522 {
1523 	usb_pipe_handle_t	pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1524 	usb_ctrl_setup_t	setup;
1525 	usb_cr_t		completion_reason;
1526 	usb_cb_flags_t		cb_flags;
1527 	wusb_cbaf_cc_data_t	cc_data;
1528 	mblk_t			*pdata = NULL;
1529 	int rval;
1530 
1531 	rval = ddi_copyin((void *)arg, &cc_data, sizeof (cc_data), flag);
1532 	if (rval != 0) {
1533 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1534 		    "ddi_copyin");
1535 
1536 		return (EIO);
1537 	}
1538 
1539 	if ((pdata = trans_from_cc_data(&cc_data)) == NULL) {
1540 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1541 		    "trans cc data");
1542 
1543 		return (EIO);
1544 	}
1545 
1546 	setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1547 	setup.bRequest =  WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1548 	setup.wValue = 0x201;
1549 	setup.wIndex = 0;
1550 	setup.wLength = WUSB_CC_DATA_SIZE;
1551 	setup.attrs = USB_ATTRS_NONE;
1552 
1553 	rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1554 	    &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1555 
1556 	freemsg(pdata);
1557 
1558 	if (rval != USB_SUCCESS) {
1559 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1560 		"cr = %d cb_flags = %d", completion_reason, cb_flags);
1561 
1562 		return (EIO);
1563 	}
1564 
1565 	return (0);
1566 }
1567 
1568 /* set failure */
1569 int
wusb_cbaf_set_failure(wusb_ca_state_t * wusb_cap,intptr_t arg,int flag)1570 wusb_cbaf_set_failure(wusb_ca_state_t *wusb_cap, intptr_t arg, int flag)
1571 {
1572 	usb_pipe_handle_t	pipe = wusb_cap->wusb_ca_reg->dev_default_ph;
1573 	usb_ctrl_setup_t	setup;
1574 	usb_cr_t		completion_reason;
1575 	usb_cb_flags_t		cb_flags;
1576 	wusb_cbaf_cc_fail_t	cc_fail;
1577 	mblk_t			*pdata = NULL;
1578 	int rval;
1579 
1580 	rval = ddi_copyin((void *)arg, &cc_fail, sizeof (cc_fail), flag);
1581 	if (rval != 0) {
1582 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1583 		    "ddi_copyin");
1584 
1585 		return (EIO);
1586 	}
1587 
1588 	if ((pdata = trans_from_cc_fail(&cc_fail)) == NULL) {
1589 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1590 		    "trans cc fail");
1591 
1592 		return (EIO);
1593 	}
1594 
1595 	setup.bmRequestType = USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
1596 	setup.bRequest =  WUSB_CBAF_SET_ASSOCIATION_RESPONSE;
1597 	setup.wValue = 0x201;
1598 	setup.wIndex = 0;
1599 	setup.wLength = WUSB_CC_DATA_SIZE;
1600 	setup.attrs = USB_ATTRS_NONE;
1601 
1602 	rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
1603 	    &completion_reason, &cb_flags, USB_FLAGS_SLEEP);
1604 
1605 	freemsg(pdata);
1606 
1607 	if (rval != USB_SUCCESS) {
1608 		USB_DPRINTF_L2(PRINT_MASK_ALL, wusb_cap->wusb_ca_log_hdl,
1609 		    "cr = %d cb_flags = %d", completion_reason, cb_flags);
1610 
1611 		return (EIO);
1612 	}
1613 
1614 	return (0);
1615 }
1616 
1617 #define	DRAW_BYTE(x, sh)	(((x) >> (sh * 8)) & 0xff)
1618 
1619 static mblk_t *
trans_from_host_info(wusb_cbaf_host_info_t * host_info)1620 trans_from_host_info(wusb_cbaf_host_info_t *host_info)
1621 {
1622 	mblk_t *pdata;
1623 
1624 	if ((pdata = allocb(WUSB_HOST_INFO_SIZE, BPRI_HI)) == NULL) {
1625 
1626 		return (NULL);
1627 	}
1628 
1629 	bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1630 	pdata->b_wptr += 4;
1631 	*pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationTypeId, 0);
1632 	*pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationTypeId, 1);
1633 
1634 	bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1635 	pdata->b_wptr += 4;
1636 	*pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationSubTypeId, 0);
1637 	*pdata->b_wptr++ = DRAW_BYTE(host_info->AssociationSubTypeId, 1);
1638 
1639 	bcopy(fieldCHID, pdata->b_wptr, 4);
1640 	pdata->b_wptr += 4;
1641 	bcopy(host_info->CHID, pdata->b_wptr, 16);
1642 	pdata->b_wptr += 16;
1643 
1644 	bcopy(fieldLangID, pdata->b_wptr, 4);
1645 	pdata->b_wptr += 4;
1646 	*pdata->b_wptr++ = DRAW_BYTE(host_info->LangID, 0);
1647 	*pdata->b_wptr++ = DRAW_BYTE(host_info->LangID, 1);
1648 
1649 	bcopy(fieldHostFriendlyName, pdata->b_wptr, 4);
1650 	pdata->b_wptr += 4;
1651 	bcopy(host_info->HostFriendlyName, pdata->b_wptr, 64);
1652 	pdata->b_wptr += 64;
1653 
1654 	return (pdata);
1655 }
1656 
1657 static mblk_t *
trans_from_cc_data(wusb_cbaf_cc_data_t * cc_data)1658 trans_from_cc_data(wusb_cbaf_cc_data_t *cc_data)
1659 {
1660 	mblk_t *pdata;
1661 
1662 	if ((pdata = allocb(WUSB_CC_DATA_SIZE, BPRI_HI)) == NULL) {
1663 
1664 		return (NULL);
1665 	}
1666 
1667 	bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1668 	pdata->b_wptr += 4;
1669 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationTypeId, 0);
1670 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationTypeId, 1);
1671 
1672 	bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1673 	pdata->b_wptr += 4;
1674 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationSubTypeId, 0);
1675 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->AssociationSubTypeId, 1);
1676 
1677 	bcopy(fieldLength, pdata->b_wptr, 4);
1678 	pdata->b_wptr += 4;
1679 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 0);
1680 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 1);
1681 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 2);
1682 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->Length, 3);
1683 
1684 	bcopy(fieldConnectionContext, pdata->b_wptr, 4);
1685 	pdata->b_wptr += 4;
1686 	bcopy(&(cc_data->CC), pdata->b_wptr, 48);
1687 	pdata->b_wptr += 48;
1688 
1689 	bcopy(fieldBandGroups, pdata->b_wptr, 4);
1690 	pdata->b_wptr += 4;
1691 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->BandGroups, 0);
1692 	*pdata->b_wptr++ = DRAW_BYTE(cc_data->BandGroups, 1);
1693 
1694 	return (pdata);
1695 }
1696 
1697 static mblk_t *
trans_from_cc_fail(wusb_cbaf_cc_fail_t * cc_fail)1698 trans_from_cc_fail(wusb_cbaf_cc_fail_t *cc_fail)
1699 {
1700 	mblk_t *pdata;
1701 
1702 	if ((pdata = allocb(WUSB_CC_FAILURE_SIZE, BPRI_HI)) == NULL) {
1703 
1704 		return (NULL);
1705 	}
1706 
1707 	bcopy(fieldAssociationTypeId, pdata->b_wptr, 4);
1708 	pdata->b_wptr += 4;
1709 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationTypeId, 0);
1710 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationTypeId, 1);
1711 
1712 	bcopy(fieldAssociationSubTypeId, pdata->b_wptr, 4);
1713 	pdata->b_wptr += 4;
1714 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationSubTypeId, 0);
1715 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationSubTypeId, 1);
1716 
1717 	bcopy(fieldLength, pdata->b_wptr, 4);
1718 	pdata->b_wptr += 4;
1719 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 0);
1720 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 1);
1721 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 2);
1722 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->Length, 3);
1723 
1724 	bcopy(fieldAssociationStatus, pdata->b_wptr, 4);
1725 	pdata->b_wptr += 4;
1726 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 0);
1727 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 1);
1728 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 2);
1729 	*pdata->b_wptr++ = DRAW_BYTE(cc_fail->AssociationStatus, 3);
1730 
1731 	return (pdata);
1732 }
1733 
1734 static int
trans_to_device_info(wusb_ca_state_t * wusb_cap,mblk_t * pdata,wusb_cbaf_device_info_t * device_info)1735 trans_to_device_info(wusb_ca_state_t *wusb_cap,
1736     mblk_t *pdata, wusb_cbaf_device_info_t *device_info)
1737 {
1738 	int i, plen;
1739 	void *paddr;
1740 	char *mode;
1741 	uchar_t *ptr = (uchar_t *)pdata->b_rptr;
1742 	wusb_cbaf_info_item_t item;
1743 
1744 	for (i = 0; i < 5; i++) {
1745 		if (((int)usb_parse_data("ss", ptr, 4, &item,
1746 		    sizeof (item))) <= 0) {
1747 			USB_DPRINTF_L2(PRINT_MASK_ALL,
1748 			    wusb_cap->wusb_ca_log_hdl,
1749 			    "parse item[%d] failed", i);
1750 
1751 			return (-1);
1752 		}
1753 		ptr += 4;
1754 
1755 		switch (item.typeID) {
1756 		case attrLength:
1757 			mode = "l";
1758 			paddr = &(device_info->Length);
1759 			plen = sizeof (uint32_t);
1760 
1761 			break;
1762 		case attrCDID:
1763 			mode = "16c";
1764 			paddr = &(device_info->CDID);
1765 			plen = 16 * sizeof (uint8_t);
1766 
1767 			break;
1768 		case attrBandGroups:
1769 			mode = "s";
1770 			paddr = &(device_info->BandGroups);
1771 			plen = sizeof (uint16_t);
1772 
1773 			break;
1774 		case attrLangID:
1775 			mode = "s";
1776 			paddr = &(device_info->LangID);
1777 			plen = sizeof (uint16_t);
1778 
1779 			break;
1780 		case attrDeviceFriendlyName:
1781 			mode = "l";
1782 			paddr = &(device_info->DeviceFriendlyName);
1783 			plen = 64 * sizeof (char);
1784 
1785 			break;
1786 		default:
1787 			USB_DPRINTF_L2(PRINT_MASK_ALL,
1788 			    wusb_cap->wusb_ca_log_hdl,
1789 			    "item[%d]: 0x%04x", i, item.typeID);
1790 
1791 			return (-1);
1792 		}
1793 
1794 		if (((int)usb_parse_data(mode, ptr, item.length,
1795 		    paddr, plen)) <= 0) {
1796 			USB_DPRINTF_L2(PRINT_MASK_ALL,
1797 			    wusb_cap->wusb_ca_log_hdl,
1798 			    "item[%d]: 0x%04x", i, item.typeID);
1799 
1800 			return (-1);
1801 		}
1802 		ptr += item.length;
1803 	}
1804 
1805 	return (0);
1806 }
1807