xref: /onnv-gate/usr/src/uts/common/io/usb/clients/hwarc/hwarc.c (revision 10912:bb04b6e33d44)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * UWB HWA Radio Controller driver.
29  *
30  *
31  * The device has four states (refer to usbai.h):
32  *	USB_DEV_ONLINE: In action or ready for action.
33  *	USB_DEV_DISCONNECTED: Hotplug removed, or device not present/correct on
34  *		resume (CPR).
35  *	USB_DEV_SUSPENDED: Device has been suspended along with the system.
36  *	USB_DEV_PWRED_DOWN: Device has been powered down.  (Note that this
37  *		driver supports only two power states, powered down and
38  *		full power.)
39  *
40  * In order to avoid race conditions between driver entry points,
41  * access to the device is serialized.	Race conditions are an issue in
42  * particular between disconnect event callbacks, detach, power, open
43  * and data transfer callbacks.  The functions hwarc_serialize/release_access
44  * are implemented for this purpose.
45  *
46  * Mutexes should never be held when making calls into USBA or when
47  * sleeping.
48  *
49  * pm_busy_component and pm_idle_component mark the device as busy or idle to
50  * the system.	These functions are paired, and are called only from code
51  * bracketed by hwarc_serialize_access and hwarc_release_access.
52  *
53  */
54 
55 #define	USBDRV_MAJOR_VER	2
56 #define	USBDRV_MINOR_VER	0
57 
58 #include <sys/strsun.h>
59 #include <sys/usb/usba.h>
60 #include <sys/usb/clients/hwarc/hwarc.h>
61 
62 
63 
64 uint_t		hwarc_errlevel		= 4;
65 static uint_t	hwarc_errmask		= (uint_t)PRINT_MASK_ALL;
66 static uint_t	hwarc_instance_debug 	= (uint_t)-1;
67 
68 static char	*name		= "hwarc";	/* Driver name, used all over */
69 
70 
71 /* Function Prototypes */
72 static int	hwarc_attach(dev_info_t *, ddi_attach_cmd_t);
73 static int	hwarc_detach(dev_info_t *, ddi_detach_cmd_t);
74 static int	hwarc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
75 static int	hwarc_cleanup(dev_info_t *, hwarc_state_t *);
76 static int	hwarc_open(dev_t *, int, int, cred_t *);
77 static int	hwarc_close(dev_t, int, int, cred_t *);
78 static int 	hwarc_send_cmd(uwb_dev_handle_t, mblk_t *, uint16_t);
79 static int	hwarc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
80 static int	hwarc_disconnect_callback(dev_info_t *);
81 static int	hwarc_reconnect_callback(dev_info_t *);
82 static void	hwarc_restore_device_state(dev_info_t *, hwarc_state_t *);
83 static int	hwarc_cpr_suspend(dev_info_t *);
84 static void	hwarc_cpr_resume(dev_info_t *);
85 static int	hwarc_open_intr_pipe(hwarc_state_t *);
86 static void	hwarc_close_intr_pipe(hwarc_state_t *);
87 static void	hwarc_pm_busy_component(hwarc_state_t *);
88 static void	hwarc_pm_idle_component(hwarc_state_t *);
89 static int	hwarc_power(dev_info_t *, int, int);
90 static int	hwarc_serialize_access(hwarc_state_t *, boolean_t);
91 static void	hwarc_release_access(hwarc_state_t *);
92 static int	hwarc_reset_device(hwarc_state_t *);
93 static int	hwarc_init_phy(hwarc_state_t *);
94 
95 
96 static int	hwarc_start_polling(hwarc_state_t *, usb_pipe_handle_t);
97 
98 
99 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
100 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_intr_req))
101 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf))
102 
103 /* module loading stuff */
104 struct cb_ops hwarc_cb_ops = {
105 	hwarc_open,		/* open  */
106 	hwarc_close,		/* close */
107 	nodev,			/* strategy */
108 	nulldev,		/* print */
109 	nulldev,		/* dump */
110 	nodev,			/* read */
111 	nodev,			/* write */
112 	hwarc_ioctl,		/* ioctl */
113 	nulldev,		/* devmap */
114 	nodev,			/* mmap */
115 	nodev,			/* segmap */
116 	nochpoll,		/* poll */
117 	ddi_prop_op,		/* cb_prop_op */
118 	NULL,			/* streamtab  */
119 	D_MP
120 };
121 
122 static struct dev_ops hwarc_ops = {
123 	DEVO_REV,		/* devo_rev, */
124 	0,			/* refcnt  */
125 	hwarc_info,		/* info */
126 	nulldev,		/* identify */
127 	nulldev,		/* probe */
128 	hwarc_attach,		/* attach */
129 	hwarc_detach,		/* detach */
130 	nodev,			/* reset */
131 	&hwarc_cb_ops,		/* driver operations */
132 	NULL,			/* bus operations */
133 	hwarc_power,		/* power */
134 	ddi_quiesce_not_needed, /* devo_quiesce */
135 };
136 
137 static struct modldrv hwarc_modldrv =	{
138 	&mod_driverops,
139 	"USB HWA Radio Controller driver",
140 	&hwarc_ops
141 };
142 
143 static struct modlinkage modlinkage = {
144 	MODREV_1,
145 	&hwarc_modldrv,
146 	NULL
147 };
148 
149 /* Soft state structures */
150 #define	HWARC_INITIAL_SOFT_SPACE	1
151 static void *hwarc_statep;
152 
153 
154 /* Module-wide initialization routine */
155 int
_init(void)156 _init(void)
157 {
158 	int rval;
159 
160 	if ((rval = ddi_soft_state_init(&hwarc_statep,
161 	    sizeof (hwarc_state_t), HWARC_INITIAL_SOFT_SPACE)) != 0) {
162 
163 		return (rval);
164 	}
165 
166 	if ((rval = mod_install(&modlinkage)) != 0) {
167 		ddi_soft_state_fini(&hwarc_statep);
168 	}
169 
170 	return (rval);
171 }
172 
173 
174 /* Module-wide tear-down routine */
175 int
_fini(void)176 _fini(void)
177 {
178 	int rval;
179 
180 	if ((rval = mod_remove(&modlinkage)) != 0) {
181 
182 		return (rval);
183 	}
184 
185 	ddi_soft_state_fini(&hwarc_statep);
186 
187 	return (rval);
188 }
189 
190 
191 int
_info(struct modinfo * modinfop)192 _info(struct modinfo *modinfop)
193 {
194 	return (mod_info(&modlinkage, modinfop));
195 }
196 
197 
198 /*
199  * hwarc_info:
200  *	Get minor number, soft state structure, etc.
201  */
202 /*ARGSUSED*/
203 static int
hwarc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)204 hwarc_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
205 			void *arg, void **result)
206 {
207 	hwarc_state_t	*hrcp;
208 	int error = DDI_FAILURE;
209 
210 	switch (infocmd) {
211 	case DDI_INFO_DEVT2DEVINFO:
212 		*result = NULL;
213 		if ((hrcp = ddi_get_soft_state(hwarc_statep,
214 		    getminor((dev_t)arg))) != NULL) {
215 			*result = hrcp->hrc_dip;
216 		}
217 		error = (*result)? DDI_SUCCESS:DDI_FAILURE;
218 
219 		break;
220 	case DDI_INFO_DEVT2INSTANCE:
221 		*result = (void *)(uintptr_t)getminor((dev_t)arg);
222 		error = DDI_SUCCESS;
223 		break;
224 	default:
225 		break;
226 	}
227 
228 	return (error);
229 }
230 
231 
232 
233 /*
234  * hwarc_init_power_mgmt:
235  *	Initialize power management and remote wakeup functionality.
236  *	No mutex is necessary in this function as it's called only by attach.
237  */
238 static void
hwarc_init_power_mgmt(hwarc_state_t * hrcp)239 hwarc_init_power_mgmt(hwarc_state_t *hrcp)
240 {
241 	hwarc_power_t	*hrcpm = NULL;
242 	uint_t		pwr_states;
243 
244 	USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
245 	    "init_power_mgmt enter");
246 
247 	/* Put online before PM init as can get power managed afterward. */
248 	hrcp->hrc_dev_state = USB_DEV_ONLINE;
249 
250 	/* Allocate the state structure */
251 	hrcpm = kmem_zalloc(sizeof (hwarc_power_t), KM_SLEEP);
252 
253 	hrcpm->hrc_state 		= hrcp;
254 	hrcpm->hrc_pm_capabilities 	= 0;
255 	hrcpm->hrc_current_power 	= USB_DEV_OS_FULL_PWR;
256 
257 
258 	if (usb_create_pm_components(hrcp->hrc_dip, &pwr_states) ==
259 	    USB_SUCCESS) {
260 		hrcpm->hrc_pwr_states 	= (uint8_t)pwr_states;
261 
262 		if (usb_handle_remote_wakeup(hrcp->hrc_dip,
263 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
264 			hrcpm->hrc_wakeup_enabled = 1;
265 		} else {
266 			USB_DPRINTF_L2(PRINT_MASK_PM,
267 			    hrcp->hrc_log_hdl, "hwarc_init_power_mgmt:"
268 			    " remote wakeup not supported");
269 		}
270 
271 	} else {
272 		USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
273 		    "hwarc_init_power_mgmt:created PM components failed");
274 	}
275 	mutex_enter(&hrcp->hrc_mutex);
276 	hrcp->hrc_pm = hrcpm;
277 	hwarc_pm_busy_component(hrcp);
278 	mutex_exit(&hrcp->hrc_mutex);
279 
280 	(void) pm_raise_power(
281 	    hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
282 
283 	USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
284 	    "hwarc_init_power_mgmt: end");
285 }
286 
287 
288 /*
289  * hwarc_destroy_power_mgmt:
290  *	Shut down and destroy power management and remote wakeup functionality.
291  */
292 static void
hwarc_destroy_power_mgmt(hwarc_state_t * hrcp)293 hwarc_destroy_power_mgmt(hwarc_state_t *hrcp)
294 {
295 	hwarc_power_t	*pm;
296 
297 	USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
298 	    "destroy_power_mgmt enter");
299 
300 	mutex_enter(&hrcp->hrc_mutex);
301 
302 	if ((pm = hrcp->hrc_pm) == NULL) {
303 		USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
304 		    "hwarc_destroy_power_mgmt:pm not supported");
305 		goto done;
306 	}
307 
308 	if (hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) {
309 		USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
310 		    "hwarc_destroy_power_mgmt:device disconnected");
311 		goto done;
312 	}
313 
314 	hwarc_pm_busy_component(hrcp);
315 
316 	mutex_exit(&hrcp->hrc_mutex);
317 
318 	if (pm->hrc_wakeup_enabled) {
319 
320 		/* First bring the device to full power */
321 		(void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
322 		if (usb_handle_remote_wakeup(hrcp->hrc_dip,
323 		    USB_REMOTE_WAKEUP_DISABLE) != USB_SUCCESS) {
324 			USB_DPRINTF_L2(PRINT_MASK_PM,
325 			    hrcp->hrc_log_hdl, "hwarc_destroy_power_mgmt: "
326 			    "Error disabling rmt wakeup");
327 		}
328 
329 	}
330 
331 	/*
332 	 * Since remote wakeup is disabled now,
333 	 * no one can raise power
334 	 * and get to device once power is lowered here.
335 	 */
336 	(void) pm_lower_power(hrcp->hrc_dip, 0, USB_DEV_OS_PWR_OFF);
337 
338 	mutex_enter(&hrcp->hrc_mutex);
339 
340 	hwarc_pm_idle_component(hrcp);
341 
342 done:
343 	if (pm) {
344 		kmem_free(pm, sizeof (hwarc_power_t));
345 
346 		hrcp->hrc_pm = NULL;
347 	}
348 	mutex_exit(&hrcp->hrc_mutex);
349 }
350 
351 
352 static void
hwarc_pm_busy_component(hwarc_state_t * hrcp)353 hwarc_pm_busy_component(hwarc_state_t *hrcp)
354 {
355 	ASSERT(mutex_owned(&hrcp->hrc_mutex));
356 
357 	USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
358 	    "hwarc_pm_busy_component: enter");
359 	if (hrcp->hrc_pm == NULL) {
360 		USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
361 		    "hwarc_pm_busy_component: pm not supported, return");
362 
363 		return;
364 	}
365 
366 	hrcp->hrc_pm->hrc_pm_busy++;
367 
368 	mutex_exit(&hrcp->hrc_mutex);
369 	if (pm_busy_component(hrcp->hrc_dip, 0) !=
370 	    DDI_SUCCESS) {
371 		mutex_enter(&hrcp->hrc_mutex);
372 		USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
373 		    "hwarc_pm_busy_component: pm busy fail, hrc_pm_busy=%d",
374 		    hrcp->hrc_pm->hrc_pm_busy);
375 
376 		hrcp->hrc_pm->hrc_pm_busy--;
377 		mutex_exit(&hrcp->hrc_mutex);
378 	}
379 	mutex_enter(&hrcp->hrc_mutex);
380 
381 	USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
382 	    "hwarc_pm_busy_component: exit");
383 }
384 
385 
386 static void
hwarc_pm_idle_component(hwarc_state_t * hrcp)387 hwarc_pm_idle_component(hwarc_state_t *hrcp)
388 {
389 	ASSERT(mutex_owned(&hrcp->hrc_mutex));
390 	USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
391 	    "hwarc_pm_idle_component: enter");
392 
393 	if (hrcp->hrc_pm == NULL) {
394 		USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
395 		    "hwarc_pm_idle_component: pm not supported");
396 
397 		return;
398 	}
399 
400 	mutex_exit(&hrcp->hrc_mutex);
401 	if (pm_idle_component(hrcp->hrc_dip, 0) == DDI_SUCCESS) {
402 		mutex_enter(&hrcp->hrc_mutex);
403 		ASSERT(hrcp->hrc_pm->hrc_pm_busy > 0);
404 		hrcp->hrc_pm->hrc_pm_busy--;
405 		mutex_exit(&hrcp->hrc_mutex);
406 	}
407 	mutex_enter(&hrcp->hrc_mutex);
408 
409 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
410 	    "hwarc_pm_idle_component: %d", hrcp->hrc_pm->hrc_pm_busy);
411 
412 }
413 
414 
415 /*
416  * hwarc_pwrlvl0:
417  * Functions to handle power transition for OS levels 0 -> 3
418  */
419 static int
hwarc_pwrlvl0(hwarc_state_t * hrcp)420 hwarc_pwrlvl0(hwarc_state_t *hrcp)
421 {
422 	int rval;
423 
424 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
425 	    "hwarc_pwrlvl0, dev_state: %x", hrcp->hrc_dev_state);
426 
427 	switch (hrcp->hrc_dev_state) {
428 		case USB_DEV_ONLINE:
429 			/* Deny the powerdown request if the device is busy */
430 			if (hrcp->hrc_pm->hrc_pm_busy != 0) {
431 				USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
432 				    "hwarc_pwrlvl0: hrc_pm_busy");
433 
434 				return (USB_FAILURE);
435 			}
436 
437 			/* Close the interrupt pipe */
438 			mutex_exit(&hrcp->hrc_mutex);
439 			hwarc_close_intr_pipe(hrcp);
440 			mutex_enter(&hrcp->hrc_mutex);
441 
442 			/* Issue USB D3 command to the device here */
443 			rval = usb_set_device_pwrlvl3(hrcp->hrc_dip);
444 			ASSERT(rval == USB_SUCCESS);
445 
446 			hrcp->hrc_dev_state = USB_DEV_PWRED_DOWN;
447 			hrcp->hrc_pm->hrc_current_power = USB_DEV_OS_PWR_OFF;
448 
449 		/* FALLTHRU */
450 		case USB_DEV_DISCONNECTED:
451 		case USB_DEV_SUSPENDED:
452 
453 			return (USB_SUCCESS);
454 
455 		case USB_DEV_PWRED_DOWN:
456 		default:
457 			USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
458 			    "hwarc_pwrlvl0: illegal dev state");
459 
460 			return (USB_FAILURE);
461 	}
462 }
463 
464 
465 /*
466  * hwarc_pwrlvl1:
467  *	Functions to handle power transition to OS levels -> 2
468  */
469 static int
hwarc_pwrlvl1(hwarc_state_t * hrcp)470 hwarc_pwrlvl1(hwarc_state_t *hrcp)
471 {
472 	int	rval;
473 
474 	USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl, "hwarc_pwrlvl1");
475 
476 	/* Issue USB D2 command to the device here */
477 	rval = usb_set_device_pwrlvl2(hrcp->hrc_dip);
478 	ASSERT(rval == USB_SUCCESS);
479 
480 	return (USB_FAILURE);
481 }
482 
483 
484 /*
485  * hwarc_pwrlvl2:
486  *	Functions to handle power transition to OS levels -> 1
487  */
488 static int
hwarc_pwrlvl2(hwarc_state_t * hrcp)489 hwarc_pwrlvl2(hwarc_state_t *hrcp)
490 {
491 	int	rval;
492 
493 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
494 	    "hwarc_pwrlvl2, dev_stat=%d", hrcp->hrc_dev_state);
495 
496 	/* Issue USB D1 command to the device here */
497 	rval = usb_set_device_pwrlvl1(hrcp->hrc_dip);
498 	ASSERT(rval == USB_SUCCESS);
499 
500 	return (USB_FAILURE);
501 }
502 
503 
504 /*
505  * hwarc_pwrlvl3:
506  *	Functions to handle power transition to OS level -> 0
507  */
508 static int
hwarc_pwrlvl3(hwarc_state_t * hrcp)509 hwarc_pwrlvl3(hwarc_state_t *hrcp)
510 {
511 
512 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
513 	    "hwarc_pwrlvl3, dev_stat=%d", hrcp->hrc_dev_state);
514 
515 	switch (hrcp->hrc_dev_state) {
516 		case USB_DEV_PWRED_DOWN:
517 			/* Issue USB D0 command to the device here */
518 			(void) usb_set_device_pwrlvl0(hrcp->hrc_dip);
519 
520 			mutex_exit(&hrcp->hrc_mutex);
521 			if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
522 				mutex_enter(&hrcp->hrc_mutex);
523 
524 				return (USB_FAILURE);
525 			}
526 			mutex_enter(&hrcp->hrc_mutex);
527 
528 			/* Todo: Reset device or not */
529 			hrcp->hrc_dev_state 		= USB_DEV_ONLINE;
530 			hrcp->hrc_pm->hrc_current_power = USB_DEV_OS_FULL_PWR;
531 
532 			/* FALLTHRU */
533 		case USB_DEV_ONLINE:
534 			/* we are already in full power */
535 			/* FALLTHRU */
536 		case USB_DEV_DISCONNECTED:
537 		case USB_DEV_SUSPENDED:
538 			/*
539 			 * PM framework tries to put us in full power
540 			 * during system shutdown. If we are disconnected/cpr'ed
541 			 * return success anyways
542 			 */
543 
544 			return (USB_SUCCESS);
545 
546 		default:
547 			USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
548 			    "hwarc_pwrlvl3: illegal dev state");
549 
550 			return (USB_FAILURE);
551 	}
552 }
553 
554 /* Init dev inst */
555 static void
hwarc_init_devinst(dev_info_t * dip,hwarc_state_t * hrcp)556 hwarc_init_devinst(dev_info_t *dip, hwarc_state_t *hrcp)
557 {
558 	char	*devinst;
559 	int	devinstlen;
560 
561 	hrcp->hrc_dip	  = dip;
562 	hrcp->hrc_log_hdl = usb_alloc_log_hdl(dip,
563 	    "hwarc", &hwarc_errlevel,
564 	    &hwarc_errmask, &hwarc_instance_debug, 0);
565 
566 	devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
567 	devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ",
568 	    ddi_driver_name(dip), ddi_get_instance(dip));
569 
570 	hrcp->hrc_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
571 	(void) strncpy(hrcp->hrc_devinst, devinst, devinstlen);
572 
573 	kmem_free(devinst, USB_MAXSTRINGLEN);
574 }
575 
576 /* init endpoints */
577 static int
hwarc_init_ep(dev_info_t * dip,hwarc_state_t * hrcp)578 hwarc_init_ep(dev_info_t *dip, hwarc_state_t *hrcp)
579 {
580 	int status = USB_SUCCESS;
581 	usb_ep_data_t	*ep_datap;
582 	if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) !=
583 	    USB_SUCCESS) {
584 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
585 		    "hwarc_init_ep: usb_client_attach failed"
586 		    " error code = %d", status);
587 		goto done;
588 	}
589 
590 	if ((status = usb_get_dev_data(dip, &hrcp->hrc_reg, USB_PARSE_LVL_ALL,
591 	    0)) != USB_SUCCESS) {
592 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
593 		    "hwarc_init_ep: usb_get_dev_data failed"
594 		    "error code = %d", status);
595 		goto done;
596 	}
597 	hrcp->hrc_if_descr =
598 	    &hrcp->hrc_reg->dev_curr_cfg->cfg_if[hrcp->hrc_reg->dev_curr_if];
599 	hrcp->hrc_default_ph = hrcp->hrc_reg->dev_default_ph;
600 
601 	/*
602 	 * Get the descriptor for an intr pipe at alt 0 of current interface.
603 	 * This will be used later to open the pipe.
604 	 */
605 	if ((ep_datap = usb_lookup_ep_data(dip, hrcp->hrc_reg,
606 	    hrcp->hrc_reg->dev_curr_if, 0, 0,
607 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) {
608 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
609 		    "hwarc_init_ep: Error getting intr endpoint descriptor");
610 		status = USB_FAILURE;
611 		goto done;
612 	}
613 	hrcp->hrc_intr_ep_descr = ep_datap->ep_descr;
614 
615 done:
616 
617 	return (status);
618 }
619 /* init mutex */
620 static void
hwarc_init_mutex(hwarc_state_t * hrcp)621 hwarc_init_mutex(hwarc_state_t *hrcp) {
622 	mutex_init(&hrcp->hrc_mutex, NULL, MUTEX_DRIVER,
623 	    hrcp->hrc_reg->dev_iblock_cookie);
624 
625 	cv_init(&hrcp->hrc_serial_cv, NULL, CV_DRIVER, NULL);
626 	hrcp->hrc_serial_inuse = B_FALSE;
627 
628 	hrcp->hrc_locks_initialized = B_TRUE;
629 }
630 /*
631  * hwarc_attach:
632  *	Attach or resume.
633  *
634  *	For attach, initialize state and device, including:
635  *		state variables, locks, device node
636  *		device registration with system
637  *		power management, hotplugging
638  *	For resume, restore device and state
639  */
640 static int
hwarc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)641 hwarc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
642 {
643 	int			instance = ddi_get_instance(dip);
644 	hwarc_state_t		*hrcp = NULL;
645 
646 	switch (cmd) {
647 		case DDI_ATTACH:
648 			break;
649 
650 		case DDI_RESUME:
651 			hwarc_cpr_resume(dip);
652 			/*
653 			 * Always return success to work around enumeration
654 			 * failures.This works around an issue where devices
655 			 * which are present before a suspend and absent upon
656 			 * resume could cause a system panic on resume.
657 			 */
658 
659 			return (DDI_SUCCESS);
660 		default:
661 			return (DDI_FAILURE);
662 	}
663 
664 	if (ddi_soft_state_zalloc(hwarc_statep, instance) == DDI_SUCCESS) {
665 		hrcp = ddi_get_soft_state(hwarc_statep, instance);
666 	}
667 	if (hrcp == NULL)  {
668 		USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL,
669 		    "hwarc_attach: get soft state failed for instance %d",
670 		    instance);
671 
672 		return (DDI_FAILURE);
673 	}
674 
675 	(void) hwarc_init_devinst(dip, hrcp);
676 
677 	if (hwarc_init_ep(dip, hrcp) != USB_SUCCESS) {
678 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
679 		    "attach: Error init usb data");
680 		goto fail;
681 	}
682 	hwarc_init_mutex(hrcp);
683 
684 	/* create minor node */
685 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
686 	    NULL, 0) != DDI_SUCCESS) {
687 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
688 		    "attach: Error creating minor node");
689 		goto fail;
690 	}
691 
692 	/* initialize power management */
693 	hwarc_init_power_mgmt(hrcp);
694 
695 	if (usb_register_hotplug_cbs(dip, hwarc_disconnect_callback,
696 	    hwarc_reconnect_callback) != USB_SUCCESS) {
697 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
698 		    "attach: Error register hotplug cbs");
699 
700 		goto fail;
701 	}
702 
703 	/* register this device to uwba */
704 	uwb_dev_attach(dip, &hrcp->hrc_dev_hdl, 0, hwarc_send_cmd);
705 
706 	if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
707 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
708 		    "attach: Error open intr pipe");
709 
710 		goto fail;
711 	}
712 
713 	/* reset device */
714 	if (hwarc_reset_device(hrcp) != USB_SUCCESS) {
715 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
716 		    "attach: Error reset deivce");
717 		goto fail;
718 	}
719 	/* init phy capabilities */
720 	if (hwarc_init_phy(hrcp) != USB_SUCCESS) {
721 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
722 		    "attach: Error get phy ie");
723 
724 		goto fail;
725 	}
726 	/* Report device */
727 	ddi_report_dev(dip);
728 
729 	mutex_enter(&hrcp->hrc_mutex);
730 	hwarc_pm_idle_component(hrcp);
731 	mutex_exit(&hrcp->hrc_mutex);
732 
733 	return (DDI_SUCCESS);
734 
735 fail:
736 	(void) hwarc_cleanup(dip, hrcp);
737 
738 	return (DDI_FAILURE);
739 }
740 
741 
742 /*
743  * hwarc_detach:
744  *	detach or suspend driver instance
745  *
746  * Note: in detach, only contention threads is from pm and disconnnect.
747  */
748 static int
hwarc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)749 hwarc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
750 {
751 	int		rval	= USB_SUCCESS;
752 	hwarc_state_t	*hrcp	=
753 	    ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
754 
755 	USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
756 	    "hwarc_detach: enter for detach, cmd = %d", cmd);
757 
758 
759 	switch (cmd) {
760 		case DDI_DETACH:
761 
762 			rval = hwarc_cleanup(dip, hrcp);
763 
764 			break;
765 		case DDI_SUSPEND:
766 
767 			rval = hwarc_cpr_suspend(dip);
768 		default:
769 
770 			break;
771 	}
772 
773 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
774 }
775 
776 
777 /*
778  * hwarc_cleanup:
779  *	clean up the driver state for detach
780  */
781 static int
hwarc_cleanup(dev_info_t * dip,hwarc_state_t * hrcp)782 hwarc_cleanup(dev_info_t *dip, hwarc_state_t *hrcp)
783 {
784 	USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "Cleanup: enter");
785 
786 	if (hrcp->hrc_locks_initialized) {
787 
788 		(void) uwb_stop_beacon(dip);
789 		/* This must be done 1st to prevent more events from coming. */
790 		usb_unregister_hotplug_cbs(dip);
791 
792 		hwarc_close_intr_pipe(hrcp);
793 
794 		/*
795 		 * At this point, no new activity can be initiated. The driver
796 		 * has disabled hotplug callbacks. The Solaris framework has
797 		 * disabled new opens on a device being detached, and does not
798 		 * allow detaching an open device.
799 		 *
800 		 * The following ensures that all driver activity has drained.
801 		 */
802 		mutex_enter(&hrcp->hrc_mutex);
803 		(void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
804 		hwarc_release_access(hrcp);
805 		mutex_exit(&hrcp->hrc_mutex);
806 
807 		/* All device activity has died down. */
808 		hwarc_destroy_power_mgmt(hrcp);
809 
810 		/* start dismantling */
811 		ddi_remove_minor_node(dip, NULL);
812 		cv_destroy(&hrcp->hrc_serial_cv);
813 		mutex_destroy(&hrcp->hrc_mutex);
814 	}
815 
816 	usb_client_detach(dip, hrcp->hrc_reg);
817 
818 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "Cleanup: end");
819 
820 	usb_free_log_hdl(hrcp->hrc_log_hdl);
821 
822 	uwb_dev_detach(hrcp->hrc_dev_hdl);
823 
824 	kmem_free(hrcp->hrc_devinst, strlen(hrcp->hrc_devinst) + 1);
825 
826 	ddi_soft_state_free(hwarc_statep, ddi_get_instance(dip));
827 	ddi_prop_remove_all(dip);
828 
829 	return (USB_SUCCESS);
830 }
831 
832 
833 
834 /*ARGSUSED*/
835 static int
hwarc_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)836 hwarc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
837 {
838 	hwarc_state_t	*hrcp = NULL;
839 	int rval = 0;
840 
841 	hrcp = ddi_get_soft_state(hwarc_statep, getminor(*devp));
842 
843 	ASSERT(hrcp != NULL);
844 
845 	USB_DPRINTF_L4(PRINT_MASK_OPEN, hrcp->hrc_log_hdl, "hwarc_open: enter");
846 
847 	/*
848 	 * Keep it simple: one client at a time.
849 	 * Exclusive open only
850 	 */
851 	mutex_enter(&hrcp->hrc_mutex);
852 	/* exclusive open */
853 	if ((flag & FEXCL) && (hrcp->hrc_open_count > 0)) {
854 		USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
855 		    "hwarc_open failed, open count=%d", hrcp->hrc_open_count);
856 		mutex_exit(&hrcp->hrc_mutex);
857 
858 		return (EBUSY);
859 	}
860 
861 	if ((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
862 	    (hrcp->hrc_dev_state == USB_DEV_SUSPENDED)) {
863 
864 		USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
865 		    "hwarc_open failed, dev_stat=%d", hrcp->hrc_dev_state);
866 		mutex_exit(&hrcp->hrc_mutex);
867 
868 		return (EIO);
869 	}
870 
871 	hrcp->hrc_open_count++;
872 
873 	USB_DPRINTF_L3(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
874 	    "hwarc_open, open count=%d", hrcp->hrc_open_count);
875 	if (hwarc_serialize_access(hrcp, HWARC_SER_SIG) == 0) {
876 		hrcp->hrc_open_count--;
877 		hwarc_release_access(hrcp);
878 		mutex_exit(&hrcp->hrc_mutex);
879 
880 		return (EINTR);
881 	}
882 
883 	hwarc_pm_busy_component(hrcp);
884 
885 	mutex_exit(&hrcp->hrc_mutex);
886 	(void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
887 
888 	mutex_enter(&hrcp->hrc_mutex);
889 	/* Fail if device is no longer ready. */
890 	if (hrcp->hrc_dev_state != USB_DEV_ONLINE) {
891 		USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
892 		    "hwarc_open failed, dev_stat=%d", hrcp->hrc_dev_state);
893 		rval = EIO;
894 	}
895 	hwarc_release_access(hrcp);
896 	/* Device specific initialization goes here. */
897 	if (rval != 0) {
898 		hrcp->hrc_open_count--;
899 		hwarc_pm_idle_component(hrcp);
900 	}
901 	mutex_exit(&hrcp->hrc_mutex);
902 
903 	USB_DPRINTF_L4(PRINT_MASK_OPEN, hrcp->hrc_log_hdl, "hwarc_open: leave");
904 
905 	return (0);
906 }
907 
908 
909 /*ARGSUSED*/
910 static int
hwarc_close(dev_t dev,int flag,int otyp,cred_t * cred_p)911 hwarc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
912 {
913 	hwarc_state_t	*hrcp =
914 	    ddi_get_soft_state(hwarc_statep, getminor(dev));
915 
916 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
917 	    "hwarc_close: enter");
918 
919 	mutex_enter(&hrcp->hrc_mutex);
920 	(void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
921 
922 	hrcp->hrc_open_count--;
923 	USB_DPRINTF_L3(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
924 	    "hwarc_close: open count=%d", hrcp->hrc_open_count);
925 
926 	hwarc_release_access(hrcp);
927 	hwarc_pm_idle_component(hrcp);
928 
929 	mutex_exit(&hrcp->hrc_mutex);
930 
931 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
932 	    "hwarc_close: leave");
933 
934 	return (0);
935 }
936 
937 /* Send cmd to hwarc device */
938 int
hwarc_send_cmd(uwb_dev_handle_t uwb_dev_hdl,mblk_t * data,uint16_t data_len)939 hwarc_send_cmd(uwb_dev_handle_t uwb_dev_hdl, mblk_t *data, uint16_t data_len)
940 {
941 	usb_cb_flags_t		cb_flags;
942 	usb_cr_t		cr;
943 	usb_ctrl_setup_t 	setup;
944 	int 			rval;
945 	hwarc_state_t		*hrcp = NULL;
946 	dev_info_t 		*dip = uwb_get_dip(uwb_dev_hdl);
947 
948 	hrcp = ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
949 
950 	ASSERT((hrcp != NULL) && (data != NULL));
951 
952 	setup.bmRequestType	= HWARC_SET_IF;
953 	setup.bRequest 		= HWA_EXEC_RC_CMD;
954 
955 	setup.wValue		= 0;
956 	setup.wIndex = hrcp->hrc_if_descr->if_alt->altif_descr.bInterfaceNumber;
957 
958 	setup.wLength		= data_len;
959 	setup.attrs		= 0;
960 
961 	USB_DPRINTF_L3(PRINT_MASK_DEVCTRL, hrcp->hrc_log_hdl,
962 	    "hwarc_send_cmd: wLength=%d, data[0], [1], [2], [3]=%d, %d, %d, %d",
963 	    setup.wLength, data->b_rptr[0], data->b_rptr[1], data->b_rptr[2],
964 	    data->b_rptr[3]);
965 
966 	if ((rval = usb_pipe_ctrl_xfer_wait(hrcp->hrc_default_ph, &setup,
967 	    &data, &cr, &cb_flags, 0)) != USB_SUCCESS) {
968 		USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, hrcp->hrc_log_hdl,
969 		    "hwarc_send_cmd: fail, rval=%d, cr=%d, "
970 		    "cb_flags=%x", rval, cr, cb_flags);
971 
972 	}
973 
974 	freemsg(data);
975 
976 	return (rval);
977 }
978 
979 /* ioctl, call uwb ioctl  */
980 /*ARGSUSED*/
981 static int
hwarc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)982 hwarc_ioctl(dev_t dev, int cmd, intptr_t arg,
983 		int mode, cred_t *cred_p, int *rval_p)
984 {
985 	int		rv = 0;
986 
987 	hwarc_state_t	*hrcp =
988 	    ddi_get_soft_state(hwarc_statep, getminor(dev));
989 	if (hrcp == NULL) {
990 
991 		return (ENXIO);
992 	}
993 
994 	if (drv_priv(cred_p) != 0) {
995 		USB_DPRINTF_L3(PRINT_MASK_ALL, hrcp->hrc_log_hdl,
996 		    "hwahc_wusb_ioctl: user must have SYS_DEVICE privilege,"
997 		    "cmd=%x", cmd);
998 
999 		return (EPERM);
1000 	}
1001 
1002 
1003 
1004 	USB_DPRINTF_L4(PRINT_MASK_ALL, hrcp->hrc_log_hdl, "hwarc_ioctl: enter");
1005 
1006 	mutex_enter(&hrcp->hrc_mutex);
1007 	if (hrcp->hrc_dev_state != USB_DEV_ONLINE) {
1008 		USB_DPRINTF_L2(PRINT_MASK_ALL, hrcp->hrc_log_hdl,
1009 		    "ioctl: Device is not online,"
1010 		    " dev_stat=%d", hrcp->hrc_dev_state);
1011 		mutex_exit(&hrcp->hrc_mutex);
1012 
1013 		return (EFAULT);
1014 	}
1015 	mutex_exit(&hrcp->hrc_mutex);
1016 
1017 	rv = uwb_do_ioctl(hrcp->hrc_dev_hdl, cmd, arg, mode);
1018 
1019 	return (rv);
1020 }
1021 
1022 
1023 /*
1024  * hwarc_disconnect_callback:
1025  *	Called when device hotplug-removed.
1026  *		Close pipes. (This does not attempt to contact device.)
1027  *		Set state to DISCONNECTED
1028  */
1029 static int
hwarc_disconnect_callback(dev_info_t * dip)1030 hwarc_disconnect_callback(dev_info_t *dip)
1031 {
1032 	hwarc_state_t	*hrcp =
1033 	    ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
1034 
1035 	USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl, "disconnect: enter");
1036 
1037 	/* Disconnect the uwb device will stop beacon and save state */
1038 	(void) uwb_dev_disconnect(dip);
1039 	hwarc_close_intr_pipe(hrcp);
1040 
1041 	mutex_enter(&hrcp->hrc_mutex);
1042 	(void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1043 
1044 	/*
1045 	 * Save any state of device or IO in progress required by
1046 	 * hwarc_restore_device_state for proper device "thawing" later.
1047 	 */
1048 	hrcp->hrc_dev_state = USB_DEV_DISCONNECTED;
1049 
1050 	hwarc_release_access(hrcp);
1051 	mutex_exit(&hrcp->hrc_mutex);
1052 
1053 	return (USB_SUCCESS);
1054 }
1055 
1056 
1057 /*
1058  * hwarc_reconnect_callback:
1059  *	Called with device hotplug-inserted
1060  *		Restore state
1061  */
1062 static int
hwarc_reconnect_callback(dev_info_t * dip)1063 hwarc_reconnect_callback(dev_info_t *dip)
1064 {
1065 	int instance = ddi_get_instance(dip);
1066 	hwarc_state_t	*hrcp =
1067 	    ddi_get_soft_state(hwarc_statep, instance);
1068 
1069 	USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl, "reconnect: enter");
1070 
1071 	mutex_enter(&hrcp->hrc_mutex);
1072 	(void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1073 	hwarc_restore_device_state(dip, hrcp);
1074 	hwarc_release_access(hrcp);
1075 	mutex_exit(&hrcp->hrc_mutex);
1076 
1077 	/* Reconnect the uwb device will restore uwb device state */
1078 	(void) uwb_dev_reconnect(dip);
1079 	return (USB_SUCCESS);
1080 }
1081 
1082 
1083 /*
1084  * hwarc_restore_device_state:
1085  *	Called during hotplug-reconnect and resume.
1086  *		reenable power management
1087  *		Verify the device is the same as before the disconnect/suspend.
1088  *		Restore device state
1089  *		Thaw any IO which was frozen.
1090  *		Quiesce device.  (Other routines will activate if thawed IO.)
1091  *		Set device online.
1092  *		Leave device disconnected if there are problems.
1093  */
1094 static void
hwarc_restore_device_state(dev_info_t * dip,hwarc_state_t * hrcp)1095 hwarc_restore_device_state(dev_info_t *dip, hwarc_state_t *hrcp)
1096 {
1097 
1098 	USB_DPRINTF_L4(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1099 	    "hwarc_restore_device_state: enter");
1100 
1101 	ASSERT(mutex_owned(&hrcp->hrc_mutex));
1102 
1103 	ASSERT((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
1104 	    (hrcp->hrc_dev_state == USB_DEV_SUSPENDED));
1105 
1106 	hwarc_pm_busy_component(hrcp);
1107 
1108 	mutex_exit(&hrcp->hrc_mutex);
1109 
1110 	(void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
1111 
1112 	if (usb_check_same_device(dip, hrcp->hrc_log_hdl, USB_LOG_L2,
1113 	    PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
1114 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1115 		    "hwarc_restore_device_state: check same device failed");
1116 
1117 		goto fail;
1118 
1119 	}
1120 	if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
1121 
1122 		goto fail;
1123 	}
1124 	mutex_enter(&hrcp->hrc_mutex);
1125 
1126 	hrcp->hrc_dev_state = USB_DEV_ONLINE;
1127 
1128 	if (hrcp->hrc_pm && hrcp->hrc_pm->hrc_wakeup_enabled) {
1129 
1130 		mutex_exit(&hrcp->hrc_mutex);
1131 		if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) !=
1132 		    USB_SUCCESS) {
1133 			USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1134 			    "hwarc_restore_device_state: "
1135 			    "fail to enable device remote wakeup");
1136 		}
1137 		mutex_enter(&hrcp->hrc_mutex);
1138 
1139 	}
1140 
1141 	hwarc_pm_idle_component(hrcp);
1142 
1143 	USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1144 	    "hwarc_restore_device_state: end");
1145 
1146 	return;
1147 
1148 fail:
1149 	/* change the device state from suspended to disconnected */
1150 	mutex_enter(&hrcp->hrc_mutex);
1151 	hrcp->hrc_dev_state = USB_DEV_DISCONNECTED;
1152 	hwarc_pm_idle_component(hrcp);
1153 }
1154 
1155 
1156 /*
1157  * hwarc_cpr_suspend:
1158  *	Clean up device.
1159  *	Wait for any IO to finish, then close pipes.
1160  *	Quiesce device.
1161  */
1162 static int
hwarc_cpr_suspend(dev_info_t * dip)1163 hwarc_cpr_suspend(dev_info_t *dip)
1164 {
1165 	hwarc_state_t	*hrcp = ddi_get_soft_state(hwarc_statep,
1166 	    ddi_get_instance(dip));
1167 
1168 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1169 	    "hwarc_cpr_suspend, dev_stat=%d", hrcp->hrc_dev_state);
1170 
1171 	/* Disconnect the uwb device will stop beacon and save state */
1172 	(void) uwb_dev_disconnect(dip);
1173 
1174 	/* Serialize to prevent races with detach, open, device access. */
1175 	mutex_enter(&hrcp->hrc_mutex);
1176 	(void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1177 
1178 	hwarc_pm_busy_component(hrcp);
1179 
1180 	/*
1181 	 * Set dev_state to suspended so other driver threads don't start any
1182 	 * new I/O.  In a real driver, there may be draining of requests done
1183 	 * afterwards, and we don't want the draining to compete with new
1184 	 * requests being queued.
1185 	 */
1186 
1187 	/* Don't suspend if the device is open. */
1188 	if (hrcp->hrc_open_count != 0) {
1189 		USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1190 		    "suspend: Device is open.  Can't suspend");
1191 
1192 		hwarc_release_access(hrcp);
1193 		hwarc_pm_idle_component(hrcp);
1194 		mutex_exit(&hrcp->hrc_mutex);
1195 
1196 		return (USB_FAILURE);
1197 	}
1198 
1199 	/* Access device here to clean it up. */
1200 	mutex_exit(&hrcp->hrc_mutex);
1201 	hwarc_close_intr_pipe(hrcp);
1202 	mutex_enter(&hrcp->hrc_mutex);
1203 
1204 	hrcp->hrc_dev_state = USB_DEV_SUSPENDED;
1205 
1206 	/*
1207 	 * Save any state of device required by hwarc_restore_device_state
1208 	 * for proper device "thawing" later.
1209 	 */
1210 	hwarc_release_access(hrcp);
1211 	hwarc_pm_idle_component(hrcp);
1212 	mutex_exit(&hrcp->hrc_mutex);
1213 
1214 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl, "suspend: success");
1215 
1216 	return (USB_SUCCESS);
1217 }
1218 
1219 
1220 /*
1221  * hwarc_cpr_resume:
1222  *
1223  *	hwarc_restore_device_state marks success by putting device back online
1224  */
1225 static void
hwarc_cpr_resume(dev_info_t * dip)1226 hwarc_cpr_resume(dev_info_t *dip)
1227 {
1228 	int		instance = ddi_get_instance(dip);
1229 	hwarc_state_t	*hrcp = ddi_get_soft_state(hwarc_statep,
1230 	    instance);
1231 
1232 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1233 	    "hwarc_cpr_resume, dev_stat=%d", hrcp->hrc_dev_state);
1234 
1235 	/*
1236 	 * NOTE: A pm_raise_power in hwarc_restore_device_state will bring
1237 	 * the power-up state of device into synch with the system.
1238 	 */
1239 	mutex_enter(&hrcp->hrc_mutex);
1240 	hwarc_restore_device_state(dip, hrcp);
1241 	mutex_exit(&hrcp->hrc_mutex);
1242 
1243 	/* Reconnect the uwb device will restore uwb device state */
1244 	(void) uwb_dev_reconnect(dip);
1245 }
1246 
1247 /*
1248  * pipe callbacks
1249  * --------------
1250  *
1251  * intr in callback for event receiving for hwarc device
1252  */
1253 /*ARGSUSED*/
1254 void
hwarc_intr_cb(usb_pipe_handle_t pipe,usb_intr_req_t * req)1255 hwarc_intr_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
1256 {
1257 	hwarc_state_t *hrcp = (hwarc_state_t *)req->intr_client_private;
1258 	uwb_dev_handle_t uwb_dev_hd;
1259 	mblk_t	*data = req->intr_data;
1260 	int		data_len, parse_err;
1261 
1262 	uwb_dev_hd = hrcp->hrc_dev_hdl;
1263 	data_len = (data) ? MBLKL(data) : 0;
1264 
1265 	if (data_len == 0) {
1266 
1267 		return;
1268 	}
1269 
1270 	/*
1271 	 * Parse the event/notifications from the device, and cv_signal the
1272 	 * waiting cmd
1273 	 */
1274 	parse_err = uwb_parse_evt_notif((uint8_t *)data->b_rptr,
1275 	    data_len, uwb_dev_hd);
1276 	if (parse_err != UWB_SUCCESS) {
1277 		USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1278 		    "hwarc_intr_cb: parse failed, no cmd result or "
1279 		    "notifs delivered. parse_err= %d", parse_err);
1280 		if (data_len >= 5) {
1281 			USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1282 			    "hwarc_intr_cb: erro evt len=%d"
1283 			    " evtcode=%d %d,evt_context=%d, result-code=%d",
1284 			    data_len, data->b_rptr[1], data->b_rptr[2],
1285 			    data->b_rptr[3], data->b_rptr[4]);
1286 		}
1287 	}
1288 
1289 	usb_free_intr_req(req);
1290 }
1291 
1292 /*
1293  * pipe callbacks
1294  * --------------
1295  *
1296  * intr in exception callback
1297  */
1298 void
hwarc_intr_ex_cb(usb_pipe_handle_t pipe,usb_intr_req_t * req)1299 hwarc_intr_ex_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
1300 {
1301 	hwarc_state_t *hrcp = (hwarc_state_t *)req->intr_client_private;
1302 	usb_cr_t	cr = req->intr_completion_reason;
1303 
1304 	USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1305 	    "hwarc_intr_ex_cb: ph = 0x%p req = 0x%p  cr=%d flags=%x",
1306 	    (void *)pipe, (void *)req, cr, req->intr_cb_flags);
1307 
1308 	usb_free_intr_req(req);
1309 
1310 	/* restart polling */
1311 	if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING) &&
1312 	    (cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
1313 	    (cr != USB_CR_PIPE_RESET) &&
1314 	    (hrcp->hrc_dev_state == USB_DEV_ONLINE)) {
1315 		if (hwarc_start_polling(hrcp, hrcp->hrc_intr_ph) !=
1316 		    USB_SUCCESS) {
1317 			USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1318 			    "hwarc_intr_ex_cb:"
1319 			    "Restart pollling failed.");
1320 		}
1321 	} else {
1322 		USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1323 		    "hwarc_intr_ex_cb:"
1324 		    "get events failed: cr=%d", cr);
1325 	}
1326 }
1327 
1328 /*
1329  * start polling on the interrupt pipe for events
1330  */
1331 int
hwarc_start_polling(hwarc_state_t * hrcp,usb_pipe_handle_t intr_ph)1332 hwarc_start_polling(hwarc_state_t *hrcp, usb_pipe_handle_t intr_ph)
1333 {
1334 	usb_intr_req_t	*br;
1335 	int		rval = USB_SUCCESS;
1336 
1337 	USB_DPRINTF_L3(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1338 	    "hwarc_start_polling");
1339 
1340 	br = usb_alloc_intr_req(hrcp->hrc_dip, 0, USB_FLAGS_SLEEP);
1341 
1342 	if (!br) {
1343 		USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1344 		    "hwarc_start_polling: alloc req failed.");
1345 
1346 		return (USB_FAILURE);
1347 	}
1348 	br->intr_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
1349 	br->intr_len = hrcp->hrc_intr_ep_descr.wMaxPacketSize;
1350 	br->intr_client_private = (void *)hrcp;
1351 
1352 	br->intr_cb = hwarc_intr_cb;
1353 	br->intr_exc_cb = hwarc_intr_ex_cb;
1354 
1355 	rval = usb_pipe_intr_xfer(intr_ph, br, USB_FLAGS_SLEEP);
1356 
1357 	if (rval != USB_SUCCESS) {
1358 		usb_free_intr_req(br);
1359 
1360 		USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1361 		    "hwarc_start_polling: failed (%d)", rval);
1362 	}
1363 
1364 	return (rval);
1365 }
1366 
1367 /*
1368  * hwarc_open_intr_pipe:
1369  *	Open any pipes other than default pipe.
1370  *	Mutex is assumed to be held.
1371  */
1372 static int
hwarc_open_intr_pipe(hwarc_state_t * hrcp)1373 hwarc_open_intr_pipe(hwarc_state_t *hrcp)
1374 {
1375 
1376 	int			rval = USB_SUCCESS;
1377 	usb_pipe_policy_t	pipe_policy;
1378 	usb_pipe_handle_t	pipe_handle;
1379 
1380 	USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "open_pipes enter");
1381 
1382 	bzero(&pipe_policy, sizeof (pipe_policy));
1383 
1384 	/*
1385 	 * Allow that pipes can support at least two asynchronous operations
1386 	 * going on simultaneously.  Operations include asynchronous callbacks,
1387 	 * resets, closures.
1388 	 */
1389 	pipe_policy.pp_max_async_reqs = 2;
1390 
1391 	if ((rval = usb_pipe_open(hrcp->hrc_dip,
1392 	    &hrcp->hrc_intr_ep_descr, &pipe_policy,
1393 	    USB_FLAGS_SLEEP, &pipe_handle)) != USB_SUCCESS) {
1394 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1395 		    "hwarc_open_intr_pipe:Error opening intr pipe: status = %d",
1396 		    rval);
1397 		goto done;
1398 	}
1399 
1400 	mutex_enter(&hrcp->hrc_mutex);
1401 	hrcp->hrc_intr_ph = pipe_handle;
1402 	mutex_exit(&hrcp->hrc_mutex);
1403 
1404 	/*
1405 	 * At this point, polling could be started on the pipe by making an
1406 	 * asynchronous input request on the pipe.  Allocate a request by
1407 	 * calling usb_alloc_intr_req(9F) with a zero length, initialize
1408 	 * attributes with USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING,
1409 	 * initialize length to be packetsize of the endpoint, specify the
1410 	 * callbacks.  Pass this request to usb_pipe_intr_xfer to start polling.
1411 	 * Call usb_pipe_stop_intr_poling(9F) to stop polling.
1412 	 */
1413 	rval = hwarc_start_polling(hrcp, hrcp->hrc_intr_ph);
1414 	if (rval != USB_SUCCESS) {
1415 		hwarc_close_intr_pipe(hrcp);
1416 
1417 		USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1418 		    "hwarc_open_intr_pipe: Error start "
1419 		    "polling intr pipe: rval = %d", rval);
1420 	}
1421 
1422 done:
1423 
1424 	return (rval);
1425 }
1426 
1427 
1428 /*
1429  * hwarc_close_intr_pipe:
1430  *	Close pipes. Mutex is assumed to be held.
1431  */
1432 static void
hwarc_close_intr_pipe(hwarc_state_t * hrcp)1433 hwarc_close_intr_pipe(hwarc_state_t *hrcp)
1434 {
1435 	usb_pipe_handle_t	pipe_handle = NULL;
1436 	USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "close_pipes enter");
1437 
1438 	mutex_enter(&hrcp->hrc_mutex);
1439 	if (!hrcp->hrc_intr_ph) {
1440 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1441 		    "hwarc intr pipe not exist");
1442 		mutex_exit(&hrcp->hrc_mutex);
1443 		return;
1444 	}
1445 
1446 	pipe_handle = hrcp->hrc_intr_ph;
1447 	hrcp->hrc_intr_ph = NULL;
1448 	mutex_exit(&hrcp->hrc_mutex);
1449 
1450 	/* Stop polling */
1451 	usb_pipe_stop_intr_polling(pipe_handle, USB_FLAGS_SLEEP);
1452 
1453 	/* Close Pipe */
1454 	usb_pipe_close(hrcp->hrc_dip, pipe_handle, USB_FLAGS_SLEEP, NULL, 0);
1455 }
1456 
1457 /*
1458  * hwarc_power :
1459  *	Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
1460  *	usb_req_raise_power and usb_req_lower_power.
1461  */
1462 /*ARGSUSED*/
1463 static int
hwarc_power(dev_info_t * dip,int comp,int level)1464 hwarc_power(dev_info_t *dip, int comp, int level)
1465 {
1466 	hwarc_state_t	*hrcp;
1467 	int	rval = USB_FAILURE;
1468 
1469 	hrcp = ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
1470 
1471 	USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1472 	    "hwarc_power: level = %d", level);
1473 
1474 	mutex_enter(&hrcp->hrc_mutex);
1475 
1476 	ASSERT(hrcp->hrc_pm != NULL);
1477 
1478 	(void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1479 
1480 	/*
1481 	 * If we are disconnected/suspended, return success. Note that if we
1482 	 * return failure, bringing down the system will hang when
1483 	 * PM tries to power up all devices
1484 	 */
1485 	if ((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
1486 	    (hrcp->hrc_dev_state == USB_DEV_SUSPENDED)) {
1487 
1488 		USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1489 		    "hwarc_power: disconnected/suspended "
1490 		    "dev_state=%d", hrcp->hrc_dev_state);
1491 		rval = USB_SUCCESS;
1492 
1493 		goto done;
1494 	}
1495 
1496 
1497 	/* Check if we are transitioning to a legal power level */
1498 	if (USB_DEV_PWRSTATE_OK(hrcp->hrc_pm->hrc_pwr_states, level)) {
1499 		USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1500 		    "hwarc_power: illegal power level = %d "
1501 		    "pwr_states: %x", level, hrcp->hrc_pm->hrc_pwr_states);
1502 
1503 		goto done;
1504 	}
1505 
1506 	switch (level) {
1507 	case USB_DEV_OS_PWR_OFF :
1508 		rval = hwarc_pwrlvl0(hrcp);
1509 
1510 		break;
1511 	case USB_DEV_OS_PWR_1:
1512 		rval = hwarc_pwrlvl1(hrcp);
1513 
1514 		break;
1515 	case USB_DEV_OS_PWR_2:
1516 		rval = hwarc_pwrlvl2(hrcp);
1517 
1518 		break;
1519 	case USB_DEV_OS_FULL_PWR :
1520 		rval = hwarc_pwrlvl3(hrcp);
1521 
1522 		break;
1523 	}
1524 
1525 done:
1526 	hwarc_release_access(hrcp);
1527 	mutex_exit(&hrcp->hrc_mutex);
1528 
1529 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1530 }
1531 
1532 
1533 /*
1534  * hwarc_serialize_access:
1535  *    Get the serial synchronization object before returning.
1536  *
1537  * Arguments:
1538  *    hrcp - Pointer to hwarc state structure
1539  *    waitsig - Set to:
1540  *	HWARC_SER_SIG - to wait such that a signal can interrupt
1541  *	HWARC_SER_NOSIG - to wait such that a signal cannot interrupt
1542  */
1543 static int
hwarc_serialize_access(hwarc_state_t * hrcp,boolean_t waitsig)1544 hwarc_serialize_access(hwarc_state_t *hrcp, boolean_t waitsig)
1545 {
1546 	int rval = 1;
1547 
1548 	ASSERT(mutex_owned(&hrcp->hrc_mutex));
1549 
1550 	while (hrcp->hrc_serial_inuse) {
1551 		if (waitsig == HWARC_SER_SIG) {
1552 			rval = cv_wait_sig(&hrcp->hrc_serial_cv,
1553 			    &hrcp->hrc_mutex);
1554 		} else {
1555 			cv_wait(&hrcp->hrc_serial_cv,
1556 			    &hrcp->hrc_mutex);
1557 		}
1558 	}
1559 	hrcp->hrc_serial_inuse = B_TRUE;
1560 
1561 	return (rval);
1562 }
1563 
1564 
1565 /*
1566  * hwarc_release_access:
1567  *    Release the serial synchronization object.
1568  */
1569 static void
hwarc_release_access(hwarc_state_t * hrcp)1570 hwarc_release_access(hwarc_state_t *hrcp)
1571 {
1572 	ASSERT(mutex_owned(&hrcp->hrc_mutex));
1573 	hrcp->hrc_serial_inuse = B_FALSE;
1574 	cv_broadcast(&hrcp->hrc_serial_cv);
1575 }
1576 
1577 
1578 /*
1579  * hwarc_reset_device:
1580  *	Reset the readio controller with uwb interfaces.
1581  *	if the device is different.  Can block.
1582  */
1583 static int
hwarc_reset_device(hwarc_state_t * hrcp)1584 hwarc_reset_device(hwarc_state_t *hrcp)
1585 {
1586 	if (uwb_reset_dev(hrcp->hrc_dip) != UWB_SUCCESS) {
1587 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1588 		    "hwarc_reset_device: uwb_reset_dev failed");
1589 
1590 		return (USB_FAILURE);
1591 	}
1592 
1593 	return (USB_SUCCESS);
1594 }
1595 
1596 /*
1597  * hwarc_init_phy
1598  *	init the physical capabilities of the radio controller.
1599  *	the band groups and phy rates will be initialized in the
1600  *	uwb devices.
1601  */
1602 static int
hwarc_init_phy(hwarc_state_t * hrcp)1603 hwarc_init_phy(hwarc_state_t *hrcp)
1604 {
1605 	if (uwb_init_phy(hrcp->hrc_dip) != UWB_SUCCESS) {
1606 		USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1607 		    "hwarc_init_phy: uwb_init_phy failed");
1608 
1609 		return (USB_FAILURE);
1610 	}
1611 
1612 	return (USB_SUCCESS);
1613 }
1614