xref: /illumos-gate/usr/src/uts/common/io/usb/usba/usbai.c (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2019, Joyent, Inc.
24  */
25 
26 
27 /*
28  * USBA: Solaris USB Architecture support
29  *
30  * all functions exposed to client drivers  have prefix usb_ while all USBA
31  * internal functions or functions exposed to HCD or hubd only have prefix
32  * usba_
33  *
34  * this file contains initializations, logging/tracing support and PM
35  * support
36  */
37 #define	USBA_FRAMEWORK
38 #include <sys/varargs.h>
39 #include <sys/strsun.h>
40 #include <sys/usb/usba/usba_impl.h>
41 #include <sys/usb/usba/hcdi_impl.h>
42 #include <sys/usb/usba/usba10.h>
43 
44 /*
45  * print buffer protected by mutex for debug stuff. the mutex also
46  * ensures serializing debug messages
47  */
48 static kmutex_t	usba_print_mutex;
49 static char usba_print_buf[USBA_PRINT_BUF_LEN];
50 kmutex_t usbai_mutex;
51 
52 /*
53  * debug stuff
54  */
55 usb_log_handle_t	usbai_log_handle;
56 uint_t			usbai_errlevel = USB_LOG_L4;
57 uint_t			usbai_errmask = (uint_t)-1;
58 
59 #define	USBA_DEBUG_SIZE_EXTRA_ALLOC	8
60 #ifdef	DEBUG
61 #define	USBA_DEBUG_BUF_SIZE \
62 			(0x40000 -  USBA_DEBUG_SIZE_EXTRA_ALLOC)
63 #else
64 #define	USBA_DEBUG_BUF_SIZE \
65 			(0x4000 -  USBA_DEBUG_SIZE_EXTRA_ALLOC)
66 #endif	/* DEBUG */
67 
68 #define	USBA_POWER_STR_SIZE		40
69 
70 int	usba_suppress_dprintf;		/* Suppress debug printing */
71 int	usba_clear_debug_buf_flag;	/* clear debug buf */
72 int	usba_buffer_dprintf = 1;	/* Use a debug print buffer */
73 int	usba_timestamp_dprintf = 0;	/* get time stamps in trace */
74 int	usba_debug_buf_size = USBA_DEBUG_BUF_SIZE;	/* Size of debug buf */
75 int	usba_debug_chatty;		/* L1 msg on console */
76 
77 static char *usba_debug_buf = NULL;	/* The debug buf */
78 static char *usba_buf_sptr, *usba_buf_eptr;
79 static hrtime_t usba_last_timestamp;	/* last time stamp in trace */
80 
81 usb_dev_cap_t usb_cap;
82 
83 /* USBA framework initializations */
84 void
85 usba_usbai_initialization()
86 {
87 	usbai_log_handle = usb_alloc_log_hdl(NULL, "usbai", &usbai_errlevel,
88 	    &usbai_errmask, NULL, 0);
89 
90 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
91 	    "usba_usbai_initialization");
92 
93 	mutex_init(&usba_print_mutex, NULL, MUTEX_DRIVER, NULL);
94 	mutex_init(&usbai_mutex, NULL, MUTEX_DRIVER, NULL);
95 }
96 
97 
98 /* USBA framework destroys */
99 void
100 usba_usbai_destroy()
101 {
102 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
103 	    "usba_usbai_destroy");
104 
105 	mutex_destroy(&usba_print_mutex);
106 	mutex_destroy(&usbai_mutex);
107 	if (usba_debug_buf) {
108 		kmem_free(usba_debug_buf,
109 		    usba_debug_buf_size + USBA_DEBUG_SIZE_EXTRA_ALLOC);
110 	}
111 
112 	usb_free_log_hdl(usbai_log_handle);
113 }
114 
115 
116 /*
117  * debug, log, and console message handling
118  */
119 usb_log_handle_t
120 usb_alloc_log_hdl(dev_info_t *dip, char *name,
121     uint_t *errlevel, uint_t *mask, uint_t *instance_filter,
122     usb_flags_t flags)
123 {
124 	usba_log_handle_impl_t	*hdl;
125 
126 	USBA_CHECK_CONTEXT();
127 	hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP);
128 
129 	hdl->lh_dip = dip;
130 	if (dip && (name == NULL)) {
131 		hdl->lh_name = (char *)ddi_driver_name(dip);
132 	} else {
133 		hdl->lh_name = name;
134 	}
135 	hdl->lh_errlevel = errlevel;
136 	hdl->lh_mask = mask;
137 	hdl->lh_instance_filter = instance_filter;
138 	hdl->lh_flags = flags;
139 
140 #ifdef __lock_lint
141 	(void) usb_alloc_log_handle(dip, name, errlevel, mask,
142 	    instance_filter, 0, flags);
143 	usb_free_log_handle(NULL);
144 #endif
145 
146 	return ((usb_log_handle_t)hdl);
147 }
148 
149 
150 /*ARGSUSED*/
151 usb_log_handle_t
152 usb_alloc_log_handle(dev_info_t *dip, char *name,
153     uint_t *errlevel, uint_t *mask, uint_t *instance_filter,
154     uint_t reserved, usb_flags_t flags)
155 {
156 	return (usb_alloc_log_hdl(dip, name, errlevel, mask,
157 	    instance_filter, flags));
158 }
159 
160 void
161 usb_free_log_handle(usb_log_handle_t handle)
162 {
163 	if (handle) {
164 		kmem_free(handle, sizeof (usba_log_handle_impl_t));
165 	}
166 }
167 
168 void
169 usb_free_log_hdl(usb_log_handle_t handle)
170 {
171 	if (handle) {
172 		kmem_free(handle, sizeof (usba_log_handle_impl_t));
173 	}
174 }
175 
176 
177 static void
178 usba_clear_dprint_buf()
179 {
180 	if (usba_debug_buf) {
181 		usba_buf_sptr = usba_debug_buf;
182 		usba_buf_eptr = usba_debug_buf + usba_debug_buf_size;
183 		bzero(usba_debug_buf, usba_debug_buf_size +
184 		    USBA_DEBUG_SIZE_EXTRA_ALLOC);
185 	}
186 }
187 
188 
189 #ifdef DEBUG
190 char *
191 usba_dbuf_tail(uint_t lines)
192 {
193 	int	count;
194 	char	*r = NULL;
195 
196 	mutex_enter(&usba_print_mutex);
197 	if (usba_debug_buf) {
198 		count = 0;
199 		r = usba_buf_sptr;
200 		while ((count < lines) && (r > usba_debug_buf)) {
201 			if (*r == '\n') {
202 				count++;
203 			}
204 			r--;
205 		}
206 	}
207 	mutex_exit(&usba_print_mutex);
208 
209 	return (r);
210 }
211 #endif	/* DEBUG */
212 
213 
214 static void usb_vprintf(dev_info_t *, int, char *, char *, va_list)
215 	__KVPRINTFLIKE(4);
216 
217 static void
218 usb_vprintf(dev_info_t *dip, int level, char *label, char *fmt, va_list ap)
219 {
220 	size_t len;
221 	int instance = 0;
222 	char driver_name[USBA_DRVNAME_LEN];
223 	char *msg_ptr;
224 
225 	if (usba_suppress_dprintf) {
226 
227 		return;
228 	}
229 
230 	*driver_name = '\0';
231 	mutex_enter(&usba_print_mutex);
232 
233 	/*
234 	 * Check if we have a valid buf size?
235 	 * Suppress logging to usb_buffer if so.
236 	 */
237 	if (usba_debug_buf_size <= 0) {
238 
239 		usba_buffer_dprintf = 0;
240 	}
241 
242 	/*
243 	 * if there is label and dip, use <driver name><instance>:
244 	 * otherwise just use the label
245 	 */
246 	if (dip) {
247 		instance = ddi_get_instance(dip);
248 		(void) snprintf(driver_name, USBA_DRVNAME_LEN,
249 		    "%s%d", ddi_driver_name(dip), instance);
250 	}
251 
252 	if (label == (char *)NULL) {
253 		len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, "\t");
254 	} else if (usba_timestamp_dprintf) {
255 		hrtime_t t = gethrtime();
256 		hrtime_t elapsed = (t - usba_last_timestamp)/1000;
257 		usba_last_timestamp = t;
258 
259 		if (dip) {
260 
261 			len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN,
262 			    "+%lld->%p: %s%d: ", elapsed,
263 			    (void *)curthread, label, instance);
264 		} else {
265 			len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN,
266 			    "+%lld->%p: %s: ", elapsed,
267 			    (void *)curthread, label);
268 		}
269 	} else {
270 		if (dip) {
271 			len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN,
272 			    "%s%d:\t", label, instance);
273 		} else {
274 			len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN,
275 			    "%s:\t", label);
276 		}
277 	}
278 
279 
280 	msg_ptr = usba_print_buf + len;
281 	(void) vsnprintf(msg_ptr, USBA_PRINT_BUF_LEN - len - 2, fmt, ap);
282 
283 	len = min(strlen(usba_print_buf), USBA_PRINT_BUF_LEN - 2);
284 	usba_print_buf[len++] = '\n';
285 	usba_print_buf[len] = '\0';
286 
287 	/*
288 	 * stuff the message in the debug buf
289 	 */
290 	if (usba_buffer_dprintf) {
291 		if (usba_debug_buf == NULL) {
292 			usba_debug_buf = kmem_alloc(
293 			    usba_debug_buf_size + USBA_DEBUG_SIZE_EXTRA_ALLOC,
294 			    KM_SLEEP);
295 			usba_clear_dprint_buf();
296 		} else if (usba_clear_debug_buf_flag) {
297 			usba_clear_dprint_buf();
298 			usba_clear_debug_buf_flag = 0;
299 		}
300 
301 		/*
302 		 * overwrite >>>> that might be over the end of the
303 		 * the buffer
304 		 */
305 		*(usba_debug_buf + usba_debug_buf_size) = '\0';
306 
307 		if ((usba_buf_sptr + len) > usba_buf_eptr) {
308 			size_t left = _PTRDIFF(usba_buf_eptr, usba_buf_sptr);
309 
310 			bcopy(usba_print_buf, usba_buf_sptr, left);
311 			bcopy((caddr_t)usba_print_buf + left,
312 			    usba_debug_buf, len - left);
313 			usba_buf_sptr = usba_debug_buf + len - left;
314 		} else {
315 			bcopy(usba_print_buf, usba_buf_sptr, len);
316 			usba_buf_sptr += len;
317 		}
318 		/* add marker */
319 		(void) sprintf(usba_buf_sptr, ">>>>");
320 	}
321 
322 	/*
323 	 * L4-L2 message may go to the log buf if not logged in usba_debug_buf
324 	 * L1 messages will go to the log buf in non-debug kernels and
325 	 * to console and log buf in debug kernels if usba_debug_chatty
326 	 * has been set
327 	 * L0 messages are warnings and will go to console and log buf and
328 	 * include the pathname, if available
329 	 */
330 
331 	switch (level) {
332 	case USB_LOG_L4:
333 	case USB_LOG_L3:
334 	case USB_LOG_L2:
335 		if (!usba_buffer_dprintf) {
336 			cmn_err(CE_CONT, "^%s", usba_print_buf);
337 		}
338 		break;
339 	case USB_LOG_L1:
340 		if (dip) {
341 			char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
342 			if (pathname) {
343 				cmn_err(CE_CONT,
344 				    usba_debug_chatty ?
345 				    "%s (%s): %s" : "?%s (%s): %s",
346 				    ddi_pathname(dip, pathname),
347 				    driver_name, msg_ptr);
348 				kmem_free(pathname, MAXPATHLEN);
349 			} else {
350 				cmn_err(CE_CONT,
351 				    usba_debug_chatty ?
352 				    "%s" : "?%s", usba_print_buf);
353 			}
354 		} else {
355 			cmn_err(CE_CONT,
356 			    usba_debug_chatty ? "%s" : "?%s",
357 			    usba_print_buf);
358 		}
359 		break;
360 	case USB_LOG_L0:
361 		/* Strip the "\n" added earlier */
362 		if (usba_print_buf[len - 1] == '\n') {
363 			usba_print_buf[len - 1] = '\0';
364 		}
365 		if (msg_ptr[len - 1] == '\n') {
366 			msg_ptr[len - 1] = '\0';
367 		}
368 		if (dip) {
369 			char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
370 			if (pathname) {
371 				cmn_err(CE_WARN, "%s (%s): %s",
372 				    ddi_pathname(dip, pathname),
373 				    driver_name, msg_ptr);
374 				kmem_free(pathname, MAXPATHLEN);
375 			} else {
376 				cmn_err(CE_WARN, usba_print_buf);
377 			}
378 		} else {
379 			cmn_err(CE_WARN, usba_print_buf);
380 		}
381 		break;
382 	}
383 
384 	mutex_exit(&usba_print_mutex);
385 }
386 
387 int
388 usba_vlog(usb_log_handle_t, uint_t, uint_t, char *, va_list)
389     __KVPRINTFLIKE(4);
390 
391 /* When usba10_calls.c goes away, this function can be made static again. */
392 int
393 usba_vlog(usb_log_handle_t handle, uint_t level, uint_t mask,
394     char *fmt, va_list ap)
395 {
396 	usba_log_handle_impl_t *hdl = (usba_log_handle_impl_t *)handle;
397 	char *label;
398 	uint_t hdl_errlevel, hdl_mask, hdl_instance_filter;
399 
400 	/* if there is no handle, use usba as label */
401 	if (hdl == NULL) {
402 		usb_vprintf(NULL, level, "usba", fmt, ap);
403 
404 		return (USB_SUCCESS);
405 	}
406 
407 	/* look up the filters and set defaults */
408 	if (hdl->lh_errlevel) {
409 		hdl_errlevel = *(hdl->lh_errlevel);
410 	} else {
411 		hdl_errlevel = 0;
412 	}
413 
414 	if (hdl->lh_mask) {
415 		hdl_mask = *(hdl->lh_mask);
416 	} else {
417 		hdl_mask = (uint_t)-1;
418 	}
419 
420 	if (hdl->lh_instance_filter) {
421 		hdl_instance_filter = *(hdl->lh_instance_filter);
422 	} else {
423 		hdl_instance_filter = (uint_t)-1;
424 	}
425 
426 	/* if threshold is lower or mask doesn't match, we are done */
427 	if ((level > hdl_errlevel) || ((mask & hdl_mask) == 0)) {
428 
429 		return (USB_FAILURE);
430 	}
431 
432 	/*
433 	 * if we have a dip, and it is not a warning, check
434 	 * the instance number
435 	 */
436 	if (hdl->lh_dip && (level > USB_LOG_L0)) {
437 		if ((hdl_instance_filter != (uint_t)-1) &&
438 		    (ddi_get_instance(hdl->lh_dip) != hdl_instance_filter)) {
439 
440 			return (USB_FAILURE);
441 		}
442 	}
443 
444 	label = hdl->lh_name;
445 
446 	usb_vprintf(hdl->lh_dip, level, label, fmt, ap);
447 
448 	return (USB_SUCCESS);
449 }
450 
451 
452 void
453 usb_dprintf4(uint_t mask, usb_log_handle_t handle, char *fmt, ...)
454 {
455 	va_list ap;
456 
457 	va_start(ap, fmt);
458 	(void) usba_vlog(handle, USB_LOG_L4, mask, fmt, ap);
459 	va_end(ap);
460 }
461 
462 
463 void
464 usb_dprintf3(uint_t mask, usb_log_handle_t handle, char *fmt, ...)
465 {
466 	va_list ap;
467 
468 	va_start(ap, fmt);
469 	(void) usba_vlog(handle, USB_LOG_L3, mask, fmt, ap);
470 	va_end(ap);
471 }
472 
473 
474 void
475 usb_dprintf2(uint_t mask, usb_log_handle_t handle, char *fmt, ...)
476 {
477 	va_list ap;
478 
479 	va_start(ap, fmt);
480 	(void) usba_vlog(handle, USB_LOG_L2, mask, fmt, ap);
481 	va_end(ap);
482 }
483 
484 
485 void
486 usb_dprintf1(uint_t mask, usb_log_handle_t handle, char *fmt, ...)
487 {
488 	va_list ap;
489 
490 	va_start(ap, fmt);
491 	(void) usba_vlog(handle, USB_LOG_L1, mask, fmt, ap);
492 	va_end(ap);
493 }
494 
495 
496 void
497 usb_dprintf0(uint_t mask, usb_log_handle_t handle, char *fmt, ...)
498 {
499 	va_list ap;
500 
501 	va_start(ap, fmt);
502 	(void) usba_vlog(handle, USB_LOG_L0, mask, fmt, ap);
503 	va_end(ap);
504 }
505 
506 
507 int
508 usb_log(usb_log_handle_t handle, uint_t level, uint_t mask, char *fmt, ...)
509 {
510 	va_list	ap;
511 	int rval;
512 
513 	va_start(ap, fmt);
514 	rval = usba_vlog(handle, level, mask, fmt, ap);
515 	va_end(ap);
516 
517 	return (rval);
518 }
519 
520 
521 /*
522  * Provide a default configuration power descriptor
523  */
524 usba_cfg_pwr_descr_t	default_cfg_power = {
525 	18,	/* bLength */
526 	USBA_DESCR_TYPE_CFG_PWR_1_1, /* bDescriptorType */
527 	0,	/* SelfPowerConsumedD0_l */
528 	0,	/* SelfPowerConsumedD0_h */
529 	0,	/* bPowerSummaryId */
530 	0,	/* bBusPowerSavingD1 */
531 	0,	/* bSelfPowerSavingD1 */
532 	0,	/* bBusPowerSavingD2 */
533 	0,	/* bSelfPowerSavingD2 */
534 	100,	/* bBusPowerSavingD3 */
535 	100,	/* bSelfPowerSavingD3 */
536 	0,	/* TransitionTimeFromD1 */
537 	0,	/* TransitionTimeFromD2 */
538 	10,	/* TransitionTimeFromD3 1 Second */
539 };
540 
541 
542 /*
543  * Provide a default interface power descriptor
544  */
545 usba_if_pwr_descr_t default_if_power = {
546 	15,	/* bLength */
547 	USBA_DESCR_TYPE_IF_PWR_1_1, /* bDescriptorType */
548 	8,	/* bmCapabilitiesFlags */
549 	0,	/* bBusPowerSavingD1 */
550 	0,	/* bSelfPowerSavingD1 */
551 	0,	/* bBusPowerSavingD2 */
552 	0,	/* bSelfPowerSavingD2 */
553 	100,	/* bBusPowerSavingD3 */
554 	100,	/* bSelfPowerSavingD3 */
555 	0,	/* TransitionTimeFromD1 */
556 	0,	/* TransitionTimeFromD2 */
557 	10,	/* TransitionTimeFromD3 1 Second */
558 };
559 
560 
561 static void
562 usba_async_req_raise_power(void *arg)
563 {
564 	usba_pm_req_t *pmrq = (usba_pm_req_t *)arg;
565 	int rval;
566 
567 	/*
568 	 * To eliminate race condition between the call to power entry
569 	 * point and our call to raise power level, we first mark the
570 	 * component busy and later idle
571 	 */
572 	(void) pm_busy_component(pmrq->dip, pmrq->comp);
573 	rval = pm_raise_power(pmrq->dip, pmrq->comp, pmrq->level);
574 	(void) pm_idle_component(pmrq->dip, pmrq->comp);
575 	pmrq->cb(pmrq->arg, rval);
576 
577 	/* We are done with pmrq. Free it now */
578 	kmem_free(pmrq, sizeof (usba_pm_req_t));
579 }
580 
581 
582 /* usb function to perform async pm_request_power_change */
583 int
584 usb_req_raise_power(dev_info_t *dip, int comp, int level,
585     void (*callback)(void *, int), void *arg, usb_flags_t flags)
586 {
587 	usba_pm_req_t *pmrq;
588 
589 	if (flags & USB_FLAGS_SLEEP) {
590 
591 		return (pm_raise_power(dip, comp, level));
592 	}
593 
594 	if ((pmrq = kmem_alloc(sizeof (usba_pm_req_t), KM_NOSLEEP)) ==
595 	    NULL) {
596 
597 		return (USB_FAILURE);
598 	}
599 
600 	pmrq->dip = dip;
601 	pmrq->comp = comp;
602 	pmrq->level = level;
603 	pmrq->cb = callback;
604 	pmrq->arg = arg;
605 	pmrq->flags = flags;
606 
607 	if (usb_async_req(dip, usba_async_req_raise_power,
608 	    (void *)pmrq, USB_FLAGS_NOSLEEP | USB_FLAGS_NOQUEUE) !=
609 	    USB_SUCCESS) {
610 		kmem_free(pmrq, sizeof (usba_pm_req_t));
611 
612 		return (USB_FAILURE);
613 	}
614 
615 	return (USB_SUCCESS);
616 }
617 
618 
619 static void
620 usba_async_req_lower_power(void *arg)
621 {
622 	usba_pm_req_t *pmrq = (usba_pm_req_t *)arg;
623 	int rval;
624 
625 	/*
626 	 * To eliminate race condition between the call to power entry
627 	 * point and our call to lower power level, we call idle component
628 	 * to push ahead the PM timestamp
629 	 */
630 	(void) pm_idle_component(pmrq->dip, pmrq->comp);
631 	rval = pm_lower_power(pmrq->dip, pmrq->comp, pmrq->level);
632 	pmrq->cb(pmrq->arg, rval);
633 }
634 
635 
636 /* usb function to perform async pm_request_power_change */
637 int
638 usb_req_lower_power(dev_info_t *dip, int comp, int level,
639     void (*callback)(void *, int), void *arg, usb_flags_t flags)
640 {
641 	usba_pm_req_t *pmrq;
642 
643 	if (flags & USB_FLAGS_SLEEP) {
644 
645 		return (pm_lower_power(dip, comp, level));
646 	}
647 
648 	if ((pmrq = kmem_alloc(sizeof (usba_pm_req_t), KM_NOSLEEP)) ==
649 	    NULL) {
650 
651 		return (USB_FAILURE);
652 	}
653 
654 	pmrq->dip = dip;
655 	pmrq->comp = comp;
656 	pmrq->level = level;
657 	pmrq->cb = callback;
658 	pmrq->arg = arg;
659 	pmrq->flags = flags;
660 
661 	if (usb_async_req(dip, usba_async_req_lower_power,
662 	    (void *)pmrq, USB_FLAGS_NOSLEEP | USB_FLAGS_NOQUEUE) !=
663 	    USB_SUCCESS) {
664 		kmem_free(pmrq, sizeof (usba_pm_req_t));
665 
666 		return (USB_FAILURE);
667 	}
668 
669 	return (USB_SUCCESS);
670 }
671 
672 
673 /* function to see if pm is enabled for this device */
674 /*ARGSUSED*/
675 int
676 usb_is_pm_enabled(dev_info_t *dip)
677 {
678 	/*
679 	 * At this point we should assume that all devices
680 	 * are capable of supporting PM
681 	 */
682 	return (USB_SUCCESS);
683 }
684 
685 
686 /*
687  * usba_handle_device_remote_wakeup:
688  *	internal function to enable/disable remote wakeup in the device
689  *	or interface
690  */
691 static int
692 usba_handle_device_remote_wakeup(dev_info_t *dip, int cmd)
693 {
694 	int		rval;
695 	uint8_t		bmRequest = USB_DEV_REQ_HOST_TO_DEV;
696 	uchar_t		bRequest;
697 	uint16_t	wIndex = 0;
698 	usb_cr_t	completion_reason = 0;
699 	usb_cb_flags_t	cb_flags;
700 	usb_pipe_handle_t ph;
701 
702 	USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle,
703 	    "usba_handle_device_remote_wakeup: dip = 0x%p", (void *)dip);
704 
705 	USBA_CHECK_CONTEXT();
706 
707 	/* get the default pipe */
708 	ph = usba_get_dflt_pipe_handle(dip);
709 
710 	/* do we own the device? */
711 	if (usb_owns_device(dip)) {
712 		bmRequest |= USB_DEV_REQ_RCPT_DEV;
713 	} else {
714 		bmRequest |= USB_DEV_REQ_RCPT_IF;
715 		wIndex = usba_get_ifno(dip);
716 	}
717 	bRequest = ((cmd == USB_REMOTE_WAKEUP_ENABLE) ? USB_REQ_SET_FEATURE :
718 	    USB_REQ_CLEAR_FEATURE);
719 
720 	if ((rval = usb_pipe_sync_ctrl_xfer(dip, ph,
721 	    bmRequest,			/* bmRequest */
722 	    bRequest,			/* bRequest */
723 	    USB_DEV_REMOTE_WAKEUP,	/* wValue */
724 	    wIndex,			/* wIndex */
725 	    0,				/* wLength */
726 	    NULL, 0,
727 	    &completion_reason,
728 	    &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) {
729 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
730 		    "Set/ClearFeature (RemoteWakep) failed: "
731 		    "rval = %d, cmd = %d, cr = 0x%x cb = 0x%x",
732 		    rval, cmd, completion_reason, cb_flags);
733 	}
734 
735 	return (rval);
736 }
737 
738 
739 void
740 usb_enable_parent_notification(dev_info_t *dip)
741 {
742 	USBA_CHECK_CONTEXT();
743 	(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
744 	    "pm-want-child-notification?");
745 }
746 
747 
748 /*
749  * usb_handle_remote_wakeup:
750  *	check if device supports remote wakeup and, if so, enable/disable
751  *	remote wake up in the device depending upon the command
752  */
753 int
754 usb_handle_remote_wakeup(dev_info_t *dip, int cmd)
755 {
756 	usb_cfg_descr_t	cfg_descr;
757 	uchar_t		*usb_cfg;	/* buf for config descriptor */
758 	size_t		cfg_length;
759 	int		rval;
760 
761 	USBA_CHECK_CONTEXT();
762 
763 	/* Obtain the raw configuration descriptor */
764 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
765 
766 	/* get configuration descriptor, must succeed */
767 	rval = usb_parse_cfg_descr(usb_cfg, cfg_length,
768 	    &cfg_descr, USB_CFG_DESCR_SIZE);
769 	ASSERT(rval == USB_CFG_DESCR_SIZE);
770 
771 	/*
772 	 * If the device supports remote wakeup, and PM is enabled,
773 	 * we enable remote wakeup in the device
774 	 */
775 	if ((usb_is_pm_enabled(dip) == USB_SUCCESS) &&
776 	    (cfg_descr.bmAttributes & USB_CFG_ATTR_REMOTE_WAKEUP)) {
777 
778 		rval = usba_handle_device_remote_wakeup(dip, cmd);
779 	} else {
780 		rval = USB_FAILURE;
781 	}
782 
783 	return (rval);
784 }
785 
786 
787 /*
788  * usb_create_pm_components:
789  *	map descriptor into  pm properties
790  */
791 int
792 usb_create_pm_components(dev_info_t *dip, uint_t *pwr_states)
793 {
794 	uchar_t			*usb_cfg;	/* buf for config descriptor */
795 	usb_cfg_descr_t		cfg_descr;
796 	size_t			cfg_length;
797 	usba_cfg_pwr_descr_t	confpwr_descr;
798 	usba_if_pwr_descr_t	ifpwr_descr;
799 	uint8_t			cfg_attrib;
800 	int			i, lvl, rval;
801 	int			n_prop = 0;
802 	uint8_t			*ptr;
803 	char			*drvname;
804 	char			str[USBA_POWER_STR_SIZE];
805 	char			*pm_comp[USBA_N_PMCOMP];
806 
807 	USBA_CHECK_CONTEXT();
808 
809 	if (usb_is_pm_enabled(dip) != USB_SUCCESS) {
810 
811 		return (USB_FAILURE);
812 	}
813 
814 	/* Obtain the raw configuration descriptor */
815 	usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length);
816 
817 	/* get configuration descriptor, must succceed */
818 	rval = usb_parse_cfg_descr(usb_cfg, cfg_length,
819 	    &cfg_descr, USB_CFG_DESCR_SIZE);
820 	ASSERT(rval == USB_CFG_DESCR_SIZE);
821 
822 	cfg_attrib = cfg_descr.bmAttributes;
823 	*pwr_states = 0;
824 
825 	/*
826 	 * Now start creating the pm-components strings
827 	 */
828 	drvname = (char *)ddi_driver_name(dip);
829 	(void) snprintf(str, USBA_POWER_STR_SIZE, "NAME= %s%d Power",
830 	    drvname, ddi_get_instance(dip));
831 
832 	pm_comp[n_prop] = kmem_zalloc(strlen(str) + 1, KM_SLEEP);
833 	(void) strcpy(pm_comp[n_prop++], str);
834 
835 	/*
836 	 * if the device is bus powered we look at the bBusPowerSavingDx
837 	 * fields else we look at bSelfPowerSavingDx fields.
838 	 * OS and USB power states are numerically reversed,
839 	 *
840 	 * Here is the mapping :-
841 	 *	OS State	USB State
842 	 *	0		D3	(minimal or no power)
843 	 *	1		D2
844 	 *	2		D1
845 	 *	3		D0	(Full power)
846 	 *
847 	 * if we own the whole device, we look at the config pwr descr
848 	 * else at the interface pwr descr.
849 	 */
850 	if (usb_owns_device(dip)) {
851 		/* Parse the configuration power descriptor */
852 		rval = usba_parse_cfg_pwr_descr(usb_cfg, cfg_length,
853 		    &confpwr_descr, USBA_CFG_PWR_DESCR_SIZE);
854 
855 		if (rval != USBA_CFG_PWR_DESCR_SIZE) {
856 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
857 			    "usb_create_pm_components: "
858 			    "usb_parse_cfg_pwr_descr returns length of %d, "
859 			    "expecting %d", rval, USBA_CFG_PWR_DESCR_SIZE);
860 
861 			return (USB_FAILURE);
862 		}
863 
864 		if (cfg_attrib & USB_CFG_ATTR_SELFPWR) {
865 			ptr = &confpwr_descr.bSelfPowerSavingD3;
866 		} else {
867 			ptr = &confpwr_descr.bBusPowerSavingD3;
868 		}
869 	} else {
870 		/* Parse the interface power descriptor */
871 		rval = usba_parse_if_pwr_descr(usb_cfg,
872 		    cfg_length,
873 		    usba_get_ifno(dip),	/* interface index */
874 		    0,			/* XXXX alt interface index */
875 		    &ifpwr_descr,
876 		    USBA_IF_PWR_DESCR_SIZE);
877 
878 		if (rval != USBA_IF_PWR_DESCR_SIZE) {
879 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
880 			    "usb_create_pm_components: "
881 			    "usb_parse_if_pwr_descr "
882 			    "returns length of %d, "
883 			    "expecting %d", rval, USBA_CFG_PWR_DESCR_SIZE);
884 
885 			return (USB_FAILURE);
886 		}
887 
888 		if (cfg_attrib & USB_CFG_ATTR_SELFPWR) {
889 			ptr =  &ifpwr_descr.bSelfPowerSavingD3;
890 		} else {
891 			ptr =  &ifpwr_descr.bBusPowerSavingD3;
892 		}
893 	}
894 
895 	/* walk thru levels and create prop level=name strings */
896 	for (lvl = USB_DEV_OS_PWR_0; lvl <= USB_DEV_OS_PWR_3; lvl++) {
897 		if (*ptr || (lvl == USB_DEV_OS_PWR_3)) {
898 			(void) snprintf(str, USBA_POWER_STR_SIZE,
899 			    "%d=USB D%d State",
900 			    lvl, USB_DEV_OS_PWR2USB_PWR(lvl));
901 			pm_comp[n_prop] = kmem_zalloc(strlen(str) + 1,
902 			    KM_SLEEP);
903 			(void) strcpy(pm_comp[n_prop++], str);
904 
905 			*pwr_states |= USB_DEV_PWRMASK(lvl);
906 		}
907 
908 		ptr -= 2; /* skip to the next power state */
909 	}
910 
911 	USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
912 	    "usb_create_pm_components: pwr_states: %x", *pwr_states);
913 
914 	/* now create the actual components */
915 	rval = ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
916 	    "pm-components", pm_comp, n_prop);
917 	if (rval == DDI_PROP_SUCCESS) {
918 		rval = USB_SUCCESS;
919 	} else {
920 		rval = USB_FAILURE;
921 	}
922 
923 	/* display & delete properties */
924 	USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
925 	    "usb_create_pm_components: The properties are:");
926 	for (i = 0; i < n_prop; i++) {
927 		USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
928 		    "\t%s", pm_comp[i]);
929 		kmem_free(pm_comp[i], strlen(pm_comp[i]) + 1);
930 	}
931 
932 	return (rval);
933 }
934 
935 
936 /*
937  * Generic Functions to set the power level of any usb device
938  *
939  * Since OS and USB power states are numerically reverse,
940  * Here is the mapping :-
941  *	OS State	USB State
942  *	0		D3	(minimal or no power)
943  *	1		D2
944  *	2		D1
945  *	3		D0	(Full power)
946  */
947 
948 /* set device power level to 0 (full power) */
949 /*ARGSUSED*/
950 int
951 usb_set_device_pwrlvl0(dev_info_t *dip)
952 {
953 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
954 	    "usb_set_device_pwrlvl0 : Not Yet Implemented");
955 
956 	return (USB_SUCCESS);
957 }
958 
959 
960 /* set device power level to 1	*/
961 /*ARGSUSED*/
962 int
963 usb_set_device_pwrlvl1(dev_info_t *dip)
964 {
965 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
966 	    "usb_set_device_pwrlvl1 : Not Yet Implemented");
967 
968 	return (USB_SUCCESS);
969 }
970 
971 
972 /* set device power level to 2	*/
973 /*ARGSUSED*/
974 int
975 usb_set_device_pwrlvl2(dev_info_t *dip)
976 {
977 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
978 	    "usb_set_device_pwrlvl2 : Not Yet Implemented");
979 
980 	return (USB_SUCCESS);
981 }
982 
983 
984 /* set device power level to 3	*/
985 /*ARGSUSED*/
986 int
987 usb_set_device_pwrlvl3(dev_info_t *dip)
988 {
989 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
990 	    "usb_set_device_pwrlvl3 : Not Yet Implemented");
991 
992 	return (USB_SUCCESS);
993 }
994 
995 
996 /*
997  * USB event management
998  */
999 typedef void (*peh_t)(dev_info_t *, ddi_eventcookie_t, void *, void *);
1000 
1001 
1002 /*
1003  * usb_register_hotplug_cbs:
1004  *	Register to get callbacks for hotplug events
1005  */
1006 /*ARGSUSED*/
1007 int
1008 usb_register_hotplug_cbs(dev_info_t *dip,
1009     int (*disconnect_event_handler)(dev_info_t *),
1010     int (*reconnect_event_handler)(dev_info_t *))
1011 {
1012 	usba_device_t		*usba_device;
1013 	usba_evdata_t		*evdata;
1014 
1015 	if ((dip == NULL) || (disconnect_event_handler == NULL) ||
1016 	    (reconnect_event_handler == NULL)) {
1017 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1018 		    "usb_register_hotplug_cbs: Bad argument(s)");
1019 
1020 		return (USB_FAILURE);
1021 	}
1022 
1023 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1024 	    "usb_register_hotplug_cbs: entry");
1025 
1026 	/*
1027 	 * The event list searches by ddi_get_eventcookie calls below, go
1028 	 * through hubd and so do not apply to host controllers.
1029 	 */
1030 	ASSERT(!usba_is_root_hub(dip));
1031 
1032 	usba_device = usba_get_usba_device(dip);
1033 	evdata = usba_get_evdata(dip);
1034 
1035 	if (usba_device->rm_cookie == NULL) {
1036 		if (ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
1037 		    &usba_device->rm_cookie) != DDI_SUCCESS) {
1038 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1039 			    "usb_register_hotplug_cbs: get rm cookie failed");
1040 
1041 			goto fail;
1042 		}
1043 	}
1044 	if (ddi_add_event_handler(dip, usba_device->rm_cookie,
1045 	    (peh_t)(uintptr_t)disconnect_event_handler,
1046 	    NULL, &evdata->ev_rm_cb_id) != DDI_SUCCESS) {
1047 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1048 		    "usb_register_hotplug_cbs: add disconnect handler failed");
1049 
1050 		goto fail;
1051 	}
1052 
1053 	if (usba_device->ins_cookie == NULL) {
1054 		if (ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
1055 		    &usba_device->ins_cookie) != DDI_SUCCESS) {
1056 			USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1057 			    "usb_register_hotplug_cbs: get ins cookie failed");
1058 
1059 			goto fail;
1060 		}
1061 	}
1062 	if (ddi_add_event_handler(dip, usba_device->ins_cookie,
1063 	    (peh_t)(uintptr_t)reconnect_event_handler,
1064 	    NULL, &evdata->ev_ins_cb_id) != DDI_SUCCESS) {
1065 		USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1066 		    "usb_register_hotplug_cbs: add reconnect handler failed");
1067 
1068 		goto fail;
1069 	}
1070 
1071 	mutex_enter(&usba_device->usb_mutex);
1072 	usba_device->usb_client_flags[usba_get_ifno(dip)] |=
1073 	    USBA_CLIENT_FLAG_EV_CBS;
1074 	usba_device->usb_client_ev_cb_list->dip = dip;
1075 	mutex_exit(&usba_device->usb_mutex);
1076 
1077 	return (USB_SUCCESS);
1078 
1079 fail:
1080 	usb_unregister_hotplug_cbs(dip);
1081 
1082 	return (USB_FAILURE);
1083 
1084 }
1085 
1086 
1087 /*
1088  * usb_unregister_hotplug_cbs:
1089  *	Unregister hotplug callbacks
1090  */
1091 /*ARGSUSED*/
1092 void
1093 usb_unregister_hotplug_cbs(dev_info_t *dip)
1094 {
1095 	usb_unregister_event_cbs(dip, NULL);
1096 }
1097 
1098 
1099 /*
1100  * usb_register_event_cbs:
1101  *	Register to get callbacks for USB events
1102  */
1103 /*ARGSUSED*/
1104 int
1105 usb_register_event_cbs(dev_info_t *dip, usb_event_t *usb_evdata,
1106     usb_flags_t flags)
1107 {
1108 	usba_device_t		*usba_device;
1109 	usba_evdata_t		*evdata;
1110 
1111 	if ((dip == NULL) || (usb_evdata == NULL)) {
1112 
1113 		return (USB_FAILURE);
1114 	}
1115 
1116 	/*
1117 	 * The event list searches by ddi_get_eventcookie calls below, go
1118 	 * through hubd and so do not apply to host controllers.
1119 	 */
1120 	ASSERT(!usba_is_root_hub(dip));
1121 
1122 	usba_device = usba_get_usba_device(dip);
1123 	evdata = usba_get_evdata(dip);
1124 
1125 	if (usb_evdata->disconnect_event_handler != NULL) {
1126 		if (usba_device->rm_cookie == NULL) {
1127 			if (ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT,
1128 			    &usba_device->rm_cookie) != DDI_SUCCESS) {
1129 
1130 				goto fail;
1131 			}
1132 		}
1133 		if (ddi_add_event_handler(dip, usba_device->rm_cookie,
1134 		    (peh_t)(uintptr_t)usb_evdata->disconnect_event_handler,
1135 		    NULL, &evdata->ev_rm_cb_id) != DDI_SUCCESS) {
1136 
1137 			goto fail;
1138 		}
1139 	}
1140 	if (usb_evdata->reconnect_event_handler != NULL) {
1141 		if (usba_device->ins_cookie == NULL) {
1142 			if (ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT,
1143 			    &usba_device->ins_cookie) != DDI_SUCCESS) {
1144 
1145 				goto fail;
1146 			}
1147 		}
1148 		if (ddi_add_event_handler(dip, usba_device->ins_cookie,
1149 		    (peh_t)(uintptr_t)usb_evdata->reconnect_event_handler,
1150 		    NULL, &evdata->ev_ins_cb_id) != DDI_SUCCESS) {
1151 
1152 			goto fail;
1153 		}
1154 	}
1155 	if (usb_evdata->post_resume_event_handler != NULL) {
1156 		if (usba_device->resume_cookie == NULL) {
1157 			if (ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT,
1158 			    &usba_device->resume_cookie) != DDI_SUCCESS) {
1159 
1160 				goto fail;
1161 			}
1162 		}
1163 		if (ddi_add_event_handler(dip, usba_device->resume_cookie,
1164 		    (peh_t)(uintptr_t)usb_evdata->post_resume_event_handler,
1165 		    NULL, &evdata->ev_resume_cb_id) != DDI_SUCCESS) {
1166 
1167 			goto fail;
1168 		}
1169 	}
1170 	if (usb_evdata->pre_suspend_event_handler != NULL) {
1171 		if (usba_device->suspend_cookie == NULL) {
1172 			if (ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT,
1173 			    &usba_device->suspend_cookie) != DDI_SUCCESS) {
1174 
1175 				goto fail;
1176 			}
1177 		}
1178 		if (ddi_add_event_handler(dip, usba_device->suspend_cookie,
1179 		    (peh_t)(uintptr_t)usb_evdata->pre_suspend_event_handler,
1180 		    NULL, &evdata->ev_suspend_cb_id) != DDI_SUCCESS) {
1181 
1182 			goto fail;
1183 		}
1184 	}
1185 
1186 	mutex_enter(&usba_device->usb_mutex);
1187 	usba_device->usb_client_flags[usba_get_ifno(dip)] |=
1188 	    USBA_CLIENT_FLAG_EV_CBS;
1189 	usba_device->usb_client_ev_cb_list->dip = dip;
1190 	usba_device->usb_client_ev_cb_list->ev_data = usb_evdata;
1191 	mutex_exit(&usba_device->usb_mutex);
1192 
1193 	return (USB_SUCCESS);
1194 
1195 fail:
1196 	usb_unregister_event_cbs(dip, usb_evdata);
1197 
1198 	return (USB_FAILURE);
1199 
1200 }
1201 
1202 
1203 /*
1204  * usb_unregister_event_cbs:
1205  *	Unregister all event callbacks
1206  */
1207 /*ARGSUSED*/
1208 void
1209 usb_unregister_event_cbs(dev_info_t *dip, usb_event_t *usb_evdata)
1210 {
1211 	usba_evdata_t		*evdata;
1212 	usba_device_t		*usba_device = usba_get_usba_device(dip);
1213 
1214 	evdata = usba_get_evdata(dip);
1215 
1216 	if (evdata->ev_rm_cb_id != NULL) {
1217 		(void) ddi_remove_event_handler(evdata->ev_rm_cb_id);
1218 		evdata->ev_rm_cb_id = NULL;
1219 	}
1220 
1221 	if (evdata->ev_ins_cb_id != NULL) {
1222 		(void) ddi_remove_event_handler(evdata->ev_ins_cb_id);
1223 		evdata->ev_ins_cb_id = NULL;
1224 	}
1225 
1226 	if (evdata->ev_suspend_cb_id != NULL) {
1227 		(void) ddi_remove_event_handler(evdata->ev_suspend_cb_id);
1228 		evdata->ev_suspend_cb_id = NULL;
1229 	}
1230 
1231 	if (evdata->ev_resume_cb_id != NULL) {
1232 		(void) ddi_remove_event_handler(evdata->ev_resume_cb_id);
1233 		evdata->ev_resume_cb_id = NULL;
1234 	}
1235 
1236 	mutex_enter(&usba_device->usb_mutex);
1237 	usba_device->usb_client_flags[usba_get_ifno(dip)] &=
1238 	    ~USBA_CLIENT_FLAG_EV_CBS;
1239 	mutex_exit(&usba_device->usb_mutex);
1240 }
1241 
1242 int
1243 usb_reset_device(dev_info_t *dip, usb_dev_reset_lvl_t reset_level)
1244 {
1245 	return (usba_hubdi_reset_device(dip, reset_level));
1246 }
1247 
1248 /*
1249  * usb device driver registration
1250  */
1251 int
1252 usb_register_dev_driver(dev_info_t *dip, usb_dev_driver_callback_t cb)
1253 {
1254 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1255 	    "usb_register_dev_driver: register the specified driver "
1256 	    "in usba: dip = 0x%p", (void *)dip);
1257 
1258 	if (cb != NULL) {
1259 		usb_cap.dip = dip;
1260 		usb_cap.usba_dev_driver_cb = cb;
1261 
1262 		return (USB_SUCCESS);
1263 	}
1264 
1265 	return (USB_FAILURE);
1266 }
1267 
1268 /*
1269  * usb device driver unregistration
1270  */
1271 void
1272 usb_unregister_dev_driver(dev_info_t *dip)
1273 {
1274 	USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1275 	    "usb_unregister_dev_driver: unregister the registered "
1276 	    "driver: dip =0x%p", (void *)dip);
1277 
1278 	ASSERT(dip == usb_cap.dip);
1279 	usb_cap.dip = NULL;
1280 	usb_cap.usba_dev_driver_cb = NULL;
1281 }
1282