17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ffcd51f3Slg150142 * Common Development and Distribution License (the "License"). 6ffcd51f3Slg150142 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 20*6f6c7d2bSVincent Wang */ 21*6f6c7d2bSVincent Wang /* 22*6f6c7d2bSVincent Wang * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate * all functions exposed to client drivers have prefix usb_ while all USBA 307c478bd9Sstevel@tonic-gate * internal functions or functions exposed to HCD or hubd only have prefix 317c478bd9Sstevel@tonic-gate * usba_ 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * this file contains initializations, logging/tracing support and PM 347c478bd9Sstevel@tonic-gate * support 357c478bd9Sstevel@tonic-gate */ 367c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK 377c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 38d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h> 397c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 404610e4a0Sfrits #include <sys/usb/usba/hcdi_impl.h> 417c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba10.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* 447c478bd9Sstevel@tonic-gate * print buffer protected by mutex for debug stuff. the mutex also 457c478bd9Sstevel@tonic-gate * ensures serializing debug messages 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate static kmutex_t usba_print_mutex; 487c478bd9Sstevel@tonic-gate static char usba_print_buf[USBA_PRINT_BUF_LEN]; 497c478bd9Sstevel@tonic-gate kmutex_t usbai_mutex; 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate /* 527c478bd9Sstevel@tonic-gate * debug stuff 537c478bd9Sstevel@tonic-gate */ 547c478bd9Sstevel@tonic-gate usb_log_handle_t usbai_log_handle; 554610e4a0Sfrits uint_t usbai_errlevel = USB_LOG_L4; 564610e4a0Sfrits uint_t usbai_errmask = (uint_t)-1; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #define USBA_DEBUG_SIZE_EXTRA_ALLOC 8 597c478bd9Sstevel@tonic-gate #ifdef DEBUG 604610e4a0Sfrits #define USBA_DEBUG_BUF_SIZE \ 614610e4a0Sfrits (0x40000 - USBA_DEBUG_SIZE_EXTRA_ALLOC) 627c478bd9Sstevel@tonic-gate #else 634610e4a0Sfrits #define USBA_DEBUG_BUF_SIZE \ 644610e4a0Sfrits (0x4000 - USBA_DEBUG_SIZE_EXTRA_ALLOC) 657c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #define USBA_POWER_STR_SIZE 40 687c478bd9Sstevel@tonic-gate 694610e4a0Sfrits int usba_suppress_dprintf; /* Suppress debug printing */ 704610e4a0Sfrits int usba_clear_debug_buf_flag; /* clear debug buf */ 714610e4a0Sfrits int usba_buffer_dprintf = 1; /* Use a debug print buffer */ 724610e4a0Sfrits int usba_timestamp_dprintf = 0; /* get time stamps in trace */ 734610e4a0Sfrits int usba_debug_buf_size = USBA_DEBUG_BUF_SIZE; /* Size of debug buf */ 744610e4a0Sfrits int usba_debug_chatty; /* L1 msg on console */ 754610e4a0Sfrits 767c478bd9Sstevel@tonic-gate static char *usba_debug_buf = NULL; /* The debug buf */ 777c478bd9Sstevel@tonic-gate static char *usba_buf_sptr, *usba_buf_eptr; 784610e4a0Sfrits static hrtime_t usba_last_timestamp; /* last time stamp in trace */ 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* USBA framework initializations */ 817c478bd9Sstevel@tonic-gate void 827c478bd9Sstevel@tonic-gate usba_usbai_initialization() 837c478bd9Sstevel@tonic-gate { 847c478bd9Sstevel@tonic-gate usbai_log_handle = usb_alloc_log_hdl(NULL, "usbai", &usbai_errlevel, 857c478bd9Sstevel@tonic-gate &usbai_errmask, NULL, 0); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 887c478bd9Sstevel@tonic-gate "usba_usbai_initialization"); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate mutex_init(&usba_print_mutex, NULL, MUTEX_DRIVER, NULL); 917c478bd9Sstevel@tonic-gate mutex_init(&usbai_mutex, NULL, MUTEX_DRIVER, NULL); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* USBA framework destroys */ 967c478bd9Sstevel@tonic-gate void 977c478bd9Sstevel@tonic-gate usba_usbai_destroy() 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1007c478bd9Sstevel@tonic-gate "usba_usbai_destroy"); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate mutex_destroy(&usba_print_mutex); 1037c478bd9Sstevel@tonic-gate mutex_destroy(&usbai_mutex); 1047c478bd9Sstevel@tonic-gate if (usba_debug_buf) { 1057c478bd9Sstevel@tonic-gate kmem_free(usba_debug_buf, 1067c478bd9Sstevel@tonic-gate usba_debug_buf_size + USBA_DEBUG_SIZE_EXTRA_ALLOC); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate usb_free_log_hdl(usbai_log_handle); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * debug, log, and console message handling 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate usb_log_handle_t 1177c478bd9Sstevel@tonic-gate usb_alloc_log_hdl(dev_info_t *dip, char *name, 1187c478bd9Sstevel@tonic-gate uint_t *errlevel, uint_t *mask, uint_t *instance_filter, 1197c478bd9Sstevel@tonic-gate usb_flags_t flags) 1207c478bd9Sstevel@tonic-gate { 1217c478bd9Sstevel@tonic-gate usba_log_handle_impl_t *hdl; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate USBA_CHECK_CONTEXT(); 1247c478bd9Sstevel@tonic-gate hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP); 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate hdl->lh_dip = dip; 1277c478bd9Sstevel@tonic-gate if (dip && (name == NULL)) { 1287c478bd9Sstevel@tonic-gate hdl->lh_name = (char *)ddi_driver_name(dip); 1297c478bd9Sstevel@tonic-gate } else { 1307c478bd9Sstevel@tonic-gate hdl->lh_name = name; 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate hdl->lh_errlevel = errlevel; 1337c478bd9Sstevel@tonic-gate hdl->lh_mask = mask; 1347c478bd9Sstevel@tonic-gate hdl->lh_instance_filter = instance_filter; 1357c478bd9Sstevel@tonic-gate hdl->lh_flags = flags; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate #ifdef __lock_lint 1387c478bd9Sstevel@tonic-gate (void) usb_alloc_log_handle(dip, name, errlevel, mask, 1397c478bd9Sstevel@tonic-gate instance_filter, 0, flags); 1407c478bd9Sstevel@tonic-gate usb_free_log_handle(NULL); 1417c478bd9Sstevel@tonic-gate #endif 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate return ((usb_log_handle_t)hdl); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1487c478bd9Sstevel@tonic-gate usb_log_handle_t 1497c478bd9Sstevel@tonic-gate usb_alloc_log_handle(dev_info_t *dip, char *name, 1507c478bd9Sstevel@tonic-gate uint_t *errlevel, uint_t *mask, uint_t *instance_filter, 1517c478bd9Sstevel@tonic-gate uint_t reserved, usb_flags_t flags) 1527c478bd9Sstevel@tonic-gate { 1537c478bd9Sstevel@tonic-gate return (usb_alloc_log_hdl(dip, name, errlevel, mask, 1547c478bd9Sstevel@tonic-gate instance_filter, flags)); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate void 1587c478bd9Sstevel@tonic-gate usb_free_log_handle(usb_log_handle_t handle) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate if (handle) { 1617c478bd9Sstevel@tonic-gate kmem_free(handle, sizeof (usba_log_handle_impl_t)); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate void 1667c478bd9Sstevel@tonic-gate usb_free_log_hdl(usb_log_handle_t handle) 1677c478bd9Sstevel@tonic-gate { 1687c478bd9Sstevel@tonic-gate if (handle) { 1697c478bd9Sstevel@tonic-gate kmem_free(handle, sizeof (usba_log_handle_impl_t)); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate static void 1757c478bd9Sstevel@tonic-gate usba_clear_dprint_buf() 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate if (usba_debug_buf) { 1787c478bd9Sstevel@tonic-gate usba_buf_sptr = usba_debug_buf; 1797c478bd9Sstevel@tonic-gate usba_buf_eptr = usba_debug_buf + usba_debug_buf_size; 1807c478bd9Sstevel@tonic-gate bzero(usba_debug_buf, usba_debug_buf_size + 1817c478bd9Sstevel@tonic-gate USBA_DEBUG_SIZE_EXTRA_ALLOC); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate #ifdef DEBUG 1877c478bd9Sstevel@tonic-gate char * 1887c478bd9Sstevel@tonic-gate usba_dbuf_tail(uint_t lines) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate int count; 1917c478bd9Sstevel@tonic-gate char *r = NULL; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate mutex_enter(&usba_print_mutex); 1947c478bd9Sstevel@tonic-gate if (usba_debug_buf) { 1957c478bd9Sstevel@tonic-gate count = 0; 1967c478bd9Sstevel@tonic-gate r = usba_buf_sptr; 1977c478bd9Sstevel@tonic-gate while ((count < lines) && (r > usba_debug_buf)) { 1987c478bd9Sstevel@tonic-gate if (*r == '\n') { 1997c478bd9Sstevel@tonic-gate count++; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate r--; 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate mutex_exit(&usba_print_mutex); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate return (r); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate static void usb_vprintf(dev_info_t *, int, char *, char *, va_list) 2127c478bd9Sstevel@tonic-gate __KVPRINTFLIKE(4); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate static void 2157c478bd9Sstevel@tonic-gate usb_vprintf(dev_info_t *dip, int level, char *label, char *fmt, va_list ap) 2167c478bd9Sstevel@tonic-gate { 2177c478bd9Sstevel@tonic-gate size_t len; 2187c478bd9Sstevel@tonic-gate int instance; 2197c478bd9Sstevel@tonic-gate char driver_name[USBA_DRVNAME_LEN]; 2207c478bd9Sstevel@tonic-gate char *msg_ptr; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if (usba_suppress_dprintf) { 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate return; 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate *driver_name = '\0'; 2287c478bd9Sstevel@tonic-gate mutex_enter(&usba_print_mutex); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Check if we have a valid buf size? 2327c478bd9Sstevel@tonic-gate * Suppress logging to usb_buffer if so. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate if (usba_debug_buf_size <= 0) { 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate usba_buffer_dprintf = 0; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * if there is label and dip, use <driver name><instance>: 2417c478bd9Sstevel@tonic-gate * otherwise just use the label 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate if (dip) { 2447c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 2457c478bd9Sstevel@tonic-gate (void) snprintf(driver_name, USBA_DRVNAME_LEN, 2467c478bd9Sstevel@tonic-gate "%s%d", ddi_driver_name(dip), instance); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (label == (char *)NULL) { 2507c478bd9Sstevel@tonic-gate len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, "\t"); 2517c478bd9Sstevel@tonic-gate } else if (usba_timestamp_dprintf) { 2527c478bd9Sstevel@tonic-gate hrtime_t t = gethrtime(); 2537c478bd9Sstevel@tonic-gate hrtime_t elapsed = (t - usba_last_timestamp)/1000; 2547c478bd9Sstevel@tonic-gate usba_last_timestamp = t; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (dip) { 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, 2597c478bd9Sstevel@tonic-gate "+%lld->%p: %s%d: ", elapsed, 2607c478bd9Sstevel@tonic-gate (void *)curthread, label, instance); 2617c478bd9Sstevel@tonic-gate } else { 2627c478bd9Sstevel@tonic-gate len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, 2637c478bd9Sstevel@tonic-gate "+%lld->%p: %s: ", elapsed, 2647c478bd9Sstevel@tonic-gate (void *)curthread, label); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate } else { 2677c478bd9Sstevel@tonic-gate if (dip) { 2687c478bd9Sstevel@tonic-gate len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, 2697c478bd9Sstevel@tonic-gate "%s%d:\t", label, instance); 2707c478bd9Sstevel@tonic-gate } else { 2717c478bd9Sstevel@tonic-gate len = snprintf(usba_print_buf, USBA_PRINT_BUF_LEN, 2727c478bd9Sstevel@tonic-gate "%s:\t", label); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate msg_ptr = usba_print_buf + len; 2787c478bd9Sstevel@tonic-gate (void) vsnprintf(msg_ptr, USBA_PRINT_BUF_LEN - len - 2, fmt, ap); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate len = min(strlen(usba_print_buf), USBA_PRINT_BUF_LEN - 2); 2817c478bd9Sstevel@tonic-gate usba_print_buf[len++] = '\n'; 2827c478bd9Sstevel@tonic-gate usba_print_buf[len] = '\0'; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * stuff the message in the debug buf 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate if (usba_buffer_dprintf) { 2887c478bd9Sstevel@tonic-gate if (usba_debug_buf == NULL) { 2897c478bd9Sstevel@tonic-gate usba_debug_buf = kmem_alloc( 2907c478bd9Sstevel@tonic-gate usba_debug_buf_size + USBA_DEBUG_SIZE_EXTRA_ALLOC, 2917c478bd9Sstevel@tonic-gate KM_SLEEP); 2927c478bd9Sstevel@tonic-gate usba_clear_dprint_buf(); 2937c478bd9Sstevel@tonic-gate } else if (usba_clear_debug_buf_flag) { 2947c478bd9Sstevel@tonic-gate usba_clear_dprint_buf(); 2957c478bd9Sstevel@tonic-gate usba_clear_debug_buf_flag = 0; 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * overwrite >>>> that might be over the end of the 3007c478bd9Sstevel@tonic-gate * the buffer 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate *(usba_debug_buf + usba_debug_buf_size) = '\0'; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if ((usba_buf_sptr + len) > usba_buf_eptr) { 305d29f5a71Szhigang lu - Sun Microsystems - Beijing China size_t left = _PTRDIFF(usba_buf_eptr, usba_buf_sptr); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate bcopy(usba_print_buf, usba_buf_sptr, left); 3087c478bd9Sstevel@tonic-gate bcopy((caddr_t)usba_print_buf + left, 3097c478bd9Sstevel@tonic-gate usba_debug_buf, len - left); 3107c478bd9Sstevel@tonic-gate usba_buf_sptr = usba_debug_buf + len - left; 3117c478bd9Sstevel@tonic-gate } else { 3127c478bd9Sstevel@tonic-gate bcopy(usba_print_buf, usba_buf_sptr, len); 3137c478bd9Sstevel@tonic-gate usba_buf_sptr += len; 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate /* add marker */ 3167c478bd9Sstevel@tonic-gate (void) sprintf(usba_buf_sptr, ">>>>"); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * L4-L2 message may go to the log buf if not logged in usba_debug_buf 3217c478bd9Sstevel@tonic-gate * L1 messages will go to the log buf in non-debug kernels and 3227c478bd9Sstevel@tonic-gate * to console and log buf in debug kernels if usba_debug_chatty 3237c478bd9Sstevel@tonic-gate * has been set 3247c478bd9Sstevel@tonic-gate * L0 messages are warnings and will go to console and log buf and 3257c478bd9Sstevel@tonic-gate * include the pathname, if available 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate switch (level) { 3297c478bd9Sstevel@tonic-gate case USB_LOG_L4: 3307c478bd9Sstevel@tonic-gate case USB_LOG_L3: 3317c478bd9Sstevel@tonic-gate case USB_LOG_L2: 3327c478bd9Sstevel@tonic-gate if (!usba_buffer_dprintf) { 3337c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "^%s", usba_print_buf); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate break; 3367c478bd9Sstevel@tonic-gate case USB_LOG_L1: 3377c478bd9Sstevel@tonic-gate if (dip) { 3387c478bd9Sstevel@tonic-gate char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); 3397c478bd9Sstevel@tonic-gate if (pathname) { 3407c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 3417c478bd9Sstevel@tonic-gate usba_debug_chatty ? 3427c478bd9Sstevel@tonic-gate "%s (%s): %s" : "?%s (%s): %s", 3437c478bd9Sstevel@tonic-gate ddi_pathname(dip, pathname), 3447c478bd9Sstevel@tonic-gate driver_name, msg_ptr); 3457c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 3467c478bd9Sstevel@tonic-gate } else { 3477c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 3487c478bd9Sstevel@tonic-gate usba_debug_chatty ? 3497c478bd9Sstevel@tonic-gate "%s" : "?%s", usba_print_buf); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate } else { 3527c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 3537c478bd9Sstevel@tonic-gate usba_debug_chatty ? "%s" : "?%s", 3547c478bd9Sstevel@tonic-gate usba_print_buf); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate break; 3577c478bd9Sstevel@tonic-gate case USB_LOG_L0: 3587c478bd9Sstevel@tonic-gate /* Strip the "\n" added earlier */ 3597c478bd9Sstevel@tonic-gate if (usba_print_buf[len - 1] == '\n') { 3607c478bd9Sstevel@tonic-gate usba_print_buf[len - 1] = '\0'; 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate if (msg_ptr[len - 1] == '\n') { 3637c478bd9Sstevel@tonic-gate msg_ptr[len - 1] = '\0'; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate if (dip) { 3667c478bd9Sstevel@tonic-gate char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP); 3677c478bd9Sstevel@tonic-gate if (pathname) { 3687c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s (%s): %s", 3697c478bd9Sstevel@tonic-gate ddi_pathname(dip, pathname), 3707c478bd9Sstevel@tonic-gate driver_name, msg_ptr); 3717c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 3727c478bd9Sstevel@tonic-gate } else { 3737c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, usba_print_buf); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate } else { 3767c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, usba_print_buf); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate break; 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate mutex_exit(&usba_print_mutex); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate int 3857c478bd9Sstevel@tonic-gate usba_vlog(usb_log_handle_t, uint_t, uint_t, char *, va_list) 3867c478bd9Sstevel@tonic-gate __KVPRINTFLIKE(4); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* When usba10_calls.c goes away, this function can be made static again. */ 3897c478bd9Sstevel@tonic-gate int 3907c478bd9Sstevel@tonic-gate usba_vlog(usb_log_handle_t handle, uint_t level, uint_t mask, 3917c478bd9Sstevel@tonic-gate char *fmt, va_list ap) 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate usba_log_handle_impl_t *hdl = (usba_log_handle_impl_t *)handle; 3947c478bd9Sstevel@tonic-gate char *label; 3957c478bd9Sstevel@tonic-gate uint_t hdl_errlevel, hdl_mask, hdl_instance_filter; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* if there is no handle, use usba as label */ 3987c478bd9Sstevel@tonic-gate if (hdl == NULL) { 3997c478bd9Sstevel@tonic-gate usb_vprintf(NULL, level, "usba", fmt, ap); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* look up the filters and set defaults */ 4057c478bd9Sstevel@tonic-gate if (hdl->lh_errlevel) { 4067c478bd9Sstevel@tonic-gate hdl_errlevel = *(hdl->lh_errlevel); 4077c478bd9Sstevel@tonic-gate } else { 4087c478bd9Sstevel@tonic-gate hdl_errlevel = 0; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (hdl->lh_mask) { 4127c478bd9Sstevel@tonic-gate hdl_mask = *(hdl->lh_mask); 4137c478bd9Sstevel@tonic-gate } else { 4147c478bd9Sstevel@tonic-gate hdl_mask = (uint_t)-1; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate if (hdl->lh_instance_filter) { 4187c478bd9Sstevel@tonic-gate hdl_instance_filter = *(hdl->lh_instance_filter); 4197c478bd9Sstevel@tonic-gate } else { 4207c478bd9Sstevel@tonic-gate hdl_instance_filter = (uint_t)-1; 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* if threshold is lower or mask doesn't match, we are done */ 4247c478bd9Sstevel@tonic-gate if ((level > hdl_errlevel) || ((mask & hdl_mask) == 0)) { 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate return (USB_FAILURE); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * if we have a dip, and it is not a warning, check 4317c478bd9Sstevel@tonic-gate * the instance number 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate if (hdl->lh_dip && (level > USB_LOG_L0)) { 4347c478bd9Sstevel@tonic-gate if ((hdl_instance_filter != (uint_t)-1) && 4357c478bd9Sstevel@tonic-gate (ddi_get_instance(hdl->lh_dip) != hdl_instance_filter)) { 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate return (USB_FAILURE); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate label = hdl->lh_name; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate usb_vprintf(hdl->lh_dip, level, label, fmt, ap); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate void 4507c478bd9Sstevel@tonic-gate usb_dprintf4(uint_t mask, usb_log_handle_t handle, char *fmt, ...) 4517c478bd9Sstevel@tonic-gate { 4527c478bd9Sstevel@tonic-gate va_list ap; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4557c478bd9Sstevel@tonic-gate (void) usba_vlog(handle, USB_LOG_L4, mask, fmt, ap); 4567c478bd9Sstevel@tonic-gate va_end(ap); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate void 4617c478bd9Sstevel@tonic-gate usb_dprintf3(uint_t mask, usb_log_handle_t handle, char *fmt, ...) 4627c478bd9Sstevel@tonic-gate { 4637c478bd9Sstevel@tonic-gate va_list ap; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4667c478bd9Sstevel@tonic-gate (void) usba_vlog(handle, USB_LOG_L3, mask, fmt, ap); 4677c478bd9Sstevel@tonic-gate va_end(ap); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate void 4727c478bd9Sstevel@tonic-gate usb_dprintf2(uint_t mask, usb_log_handle_t handle, char *fmt, ...) 4737c478bd9Sstevel@tonic-gate { 4747c478bd9Sstevel@tonic-gate va_list ap; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4777c478bd9Sstevel@tonic-gate (void) usba_vlog(handle, USB_LOG_L2, mask, fmt, ap); 4787c478bd9Sstevel@tonic-gate va_end(ap); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate void 4837c478bd9Sstevel@tonic-gate usb_dprintf1(uint_t mask, usb_log_handle_t handle, char *fmt, ...) 4847c478bd9Sstevel@tonic-gate { 4857c478bd9Sstevel@tonic-gate va_list ap; 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4887c478bd9Sstevel@tonic-gate (void) usba_vlog(handle, USB_LOG_L1, mask, fmt, ap); 4897c478bd9Sstevel@tonic-gate va_end(ap); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate void 4947c478bd9Sstevel@tonic-gate usb_dprintf0(uint_t mask, usb_log_handle_t handle, char *fmt, ...) 4957c478bd9Sstevel@tonic-gate { 4967c478bd9Sstevel@tonic-gate va_list ap; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4997c478bd9Sstevel@tonic-gate (void) usba_vlog(handle, USB_LOG_L0, mask, fmt, ap); 5007c478bd9Sstevel@tonic-gate va_end(ap); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate int 5057c478bd9Sstevel@tonic-gate usb_log(usb_log_handle_t handle, uint_t level, uint_t mask, char *fmt, ...) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate va_list ap; 5087c478bd9Sstevel@tonic-gate int rval; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate va_start(ap, fmt); 5117c478bd9Sstevel@tonic-gate rval = usba_vlog(handle, level, mask, fmt, ap); 5127c478bd9Sstevel@tonic-gate va_end(ap); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate return (rval); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* 5197c478bd9Sstevel@tonic-gate * Provide a default configuration power descriptor 5207c478bd9Sstevel@tonic-gate */ 5217c478bd9Sstevel@tonic-gate usba_cfg_pwr_descr_t default_cfg_power = { 5227c478bd9Sstevel@tonic-gate 18, /* bLength */ 5237c478bd9Sstevel@tonic-gate USBA_DESCR_TYPE_CFG_PWR_1_1, /* bDescriptorType */ 5247c478bd9Sstevel@tonic-gate 0, /* SelfPowerConsumedD0_l */ 5257c478bd9Sstevel@tonic-gate 0, /* SelfPowerConsumedD0_h */ 5267c478bd9Sstevel@tonic-gate 0, /* bPowerSummaryId */ 5277c478bd9Sstevel@tonic-gate 0, /* bBusPowerSavingD1 */ 5287c478bd9Sstevel@tonic-gate 0, /* bSelfPowerSavingD1 */ 5297c478bd9Sstevel@tonic-gate 0, /* bBusPowerSavingD2 */ 5307c478bd9Sstevel@tonic-gate 0, /* bSelfPowerSavingD2 */ 5317c478bd9Sstevel@tonic-gate 100, /* bBusPowerSavingD3 */ 5327c478bd9Sstevel@tonic-gate 100, /* bSelfPowerSavingD3 */ 5337c478bd9Sstevel@tonic-gate 0, /* TransitionTimeFromD1 */ 5347c478bd9Sstevel@tonic-gate 0, /* TransitionTimeFromD2 */ 5357c478bd9Sstevel@tonic-gate 10, /* TransitionTimeFromD3 1 Second */ 5367c478bd9Sstevel@tonic-gate }; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * Provide a default interface power descriptor 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate usba_if_pwr_descr_t default_if_power = { 5437c478bd9Sstevel@tonic-gate 15, /* bLength */ 5447c478bd9Sstevel@tonic-gate USBA_DESCR_TYPE_IF_PWR_1_1, /* bDescriptorType */ 5457c478bd9Sstevel@tonic-gate 8, /* bmCapabilitiesFlags */ 5467c478bd9Sstevel@tonic-gate 0, /* bBusPowerSavingD1 */ 5477c478bd9Sstevel@tonic-gate 0, /* bSelfPowerSavingD1 */ 5487c478bd9Sstevel@tonic-gate 0, /* bBusPowerSavingD2 */ 5497c478bd9Sstevel@tonic-gate 0, /* bSelfPowerSavingD2 */ 5507c478bd9Sstevel@tonic-gate 100, /* bBusPowerSavingD3 */ 5517c478bd9Sstevel@tonic-gate 100, /* bSelfPowerSavingD3 */ 5527c478bd9Sstevel@tonic-gate 0, /* TransitionTimeFromD1 */ 5537c478bd9Sstevel@tonic-gate 0, /* TransitionTimeFromD2 */ 5547c478bd9Sstevel@tonic-gate 10, /* TransitionTimeFromD3 1 Second */ 5557c478bd9Sstevel@tonic-gate }; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate static void 5597c478bd9Sstevel@tonic-gate usba_async_req_raise_power(void *arg) 5607c478bd9Sstevel@tonic-gate { 5617c478bd9Sstevel@tonic-gate usba_pm_req_t *pmrq = (usba_pm_req_t *)arg; 5627c478bd9Sstevel@tonic-gate int rval; 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * To eliminate race condition between the call to power entry 5667c478bd9Sstevel@tonic-gate * point and our call to raise power level, we first mark the 5677c478bd9Sstevel@tonic-gate * component busy and later idle 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate (void) pm_busy_component(pmrq->dip, pmrq->comp); 5707c478bd9Sstevel@tonic-gate rval = pm_raise_power(pmrq->dip, pmrq->comp, pmrq->level); 5717c478bd9Sstevel@tonic-gate (void) pm_idle_component(pmrq->dip, pmrq->comp); 5727c478bd9Sstevel@tonic-gate pmrq->cb(pmrq->arg, rval); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate /* We are done with pmrq. Free it now */ 5757c478bd9Sstevel@tonic-gate kmem_free(pmrq, sizeof (usba_pm_req_t)); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate /* usb function to perform async pm_request_power_change */ 5807c478bd9Sstevel@tonic-gate int 5817c478bd9Sstevel@tonic-gate usb_req_raise_power(dev_info_t *dip, int comp, int level, 5827c478bd9Sstevel@tonic-gate void (*callback)(void *, int), void *arg, usb_flags_t flags) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate usba_pm_req_t *pmrq; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if (flags & USB_FLAGS_SLEEP) { 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate return (pm_raise_power(dip, comp, level)); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate if ((pmrq = kmem_alloc(sizeof (usba_pm_req_t), KM_NOSLEEP)) == 5927c478bd9Sstevel@tonic-gate NULL) { 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate return (USB_FAILURE); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate pmrq->dip = dip; 5987c478bd9Sstevel@tonic-gate pmrq->comp = comp; 5997c478bd9Sstevel@tonic-gate pmrq->level = level; 6007c478bd9Sstevel@tonic-gate pmrq->cb = callback; 6017c478bd9Sstevel@tonic-gate pmrq->arg = arg; 6027c478bd9Sstevel@tonic-gate pmrq->flags = flags; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (usb_async_req(dip, usba_async_req_raise_power, 6057c478bd9Sstevel@tonic-gate (void *)pmrq, USB_FLAGS_NOSLEEP | USB_FLAGS_NOQUEUE) != 6067c478bd9Sstevel@tonic-gate USB_SUCCESS) { 6077c478bd9Sstevel@tonic-gate kmem_free(pmrq, sizeof (usba_pm_req_t)); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate return (USB_FAILURE); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate static void 6177c478bd9Sstevel@tonic-gate usba_async_req_lower_power(void *arg) 6187c478bd9Sstevel@tonic-gate { 6197c478bd9Sstevel@tonic-gate usba_pm_req_t *pmrq = (usba_pm_req_t *)arg; 6207c478bd9Sstevel@tonic-gate int rval; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* 6237c478bd9Sstevel@tonic-gate * To eliminate race condition between the call to power entry 6247c478bd9Sstevel@tonic-gate * point and our call to lower power level, we call idle component 6257c478bd9Sstevel@tonic-gate * to push ahead the PM timestamp 6267c478bd9Sstevel@tonic-gate */ 6277c478bd9Sstevel@tonic-gate (void) pm_idle_component(pmrq->dip, pmrq->comp); 6287c478bd9Sstevel@tonic-gate rval = pm_lower_power(pmrq->dip, pmrq->comp, pmrq->level); 6297c478bd9Sstevel@tonic-gate pmrq->cb(pmrq->arg, rval); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* usb function to perform async pm_request_power_change */ 6347c478bd9Sstevel@tonic-gate int 6357c478bd9Sstevel@tonic-gate usb_req_lower_power(dev_info_t *dip, int comp, int level, 6367c478bd9Sstevel@tonic-gate void (*callback)(void *, int), void *arg, usb_flags_t flags) 6377c478bd9Sstevel@tonic-gate { 6387c478bd9Sstevel@tonic-gate usba_pm_req_t *pmrq; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate if (flags & USB_FLAGS_SLEEP) { 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate return (pm_lower_power(dip, comp, level)); 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if ((pmrq = kmem_alloc(sizeof (usba_pm_req_t), KM_NOSLEEP)) == 6467c478bd9Sstevel@tonic-gate NULL) { 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate return (USB_FAILURE); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate pmrq->dip = dip; 6527c478bd9Sstevel@tonic-gate pmrq->comp = comp; 6537c478bd9Sstevel@tonic-gate pmrq->level = level; 6547c478bd9Sstevel@tonic-gate pmrq->cb = callback; 6557c478bd9Sstevel@tonic-gate pmrq->arg = arg; 6567c478bd9Sstevel@tonic-gate pmrq->flags = flags; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate if (usb_async_req(dip, usba_async_req_lower_power, 6597c478bd9Sstevel@tonic-gate (void *)pmrq, USB_FLAGS_NOSLEEP | USB_FLAGS_NOQUEUE) != 6607c478bd9Sstevel@tonic-gate USB_SUCCESS) { 6617c478bd9Sstevel@tonic-gate kmem_free(pmrq, sizeof (usba_pm_req_t)); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate return (USB_FAILURE); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate /* function to see if pm is enabled for this device */ 6717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6727c478bd9Sstevel@tonic-gate int 6737c478bd9Sstevel@tonic-gate usb_is_pm_enabled(dev_info_t *dip) 6747c478bd9Sstevel@tonic-gate { 675*6f6c7d2bSVincent Wang /* 676*6f6c7d2bSVincent Wang * At this point we should assume that all devices 677*6f6c7d2bSVincent Wang * are capable of supporting PM 678*6f6c7d2bSVincent Wang */ 6797c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* 6847c478bd9Sstevel@tonic-gate * usba_handle_device_remote_wakeup: 6857c478bd9Sstevel@tonic-gate * internal function to enable/disable remote wakeup in the device 6867c478bd9Sstevel@tonic-gate * or interface 6877c478bd9Sstevel@tonic-gate */ 6887c478bd9Sstevel@tonic-gate static int 6897c478bd9Sstevel@tonic-gate usba_handle_device_remote_wakeup(dev_info_t *dip, int cmd) 6907c478bd9Sstevel@tonic-gate { 6917c478bd9Sstevel@tonic-gate int rval; 6927c478bd9Sstevel@tonic-gate uint8_t bmRequest = USB_DEV_REQ_HOST_TO_DEV; 6937c478bd9Sstevel@tonic-gate uchar_t bRequest; 6947c478bd9Sstevel@tonic-gate uint16_t wIndex = 0; 6957c478bd9Sstevel@tonic-gate usb_cr_t completion_reason = 0; 6967c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags; 6977c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBA, usbai_log_handle, 700112116d8Sfb209375 "usba_handle_device_remote_wakeup: dip = 0x%p", (void *)dip); 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate USBA_CHECK_CONTEXT(); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate /* get the default pipe */ 7057c478bd9Sstevel@tonic-gate ph = usba_get_dflt_pipe_handle(dip); 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* do we own the device? */ 7087c478bd9Sstevel@tonic-gate if (usb_owns_device(dip)) { 7097c478bd9Sstevel@tonic-gate bmRequest |= USB_DEV_REQ_RCPT_DEV; 7107c478bd9Sstevel@tonic-gate } else { 7117c478bd9Sstevel@tonic-gate bmRequest |= USB_DEV_REQ_RCPT_IF; 7127c478bd9Sstevel@tonic-gate wIndex = usba_get_ifno(dip); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate bRequest = ((cmd == USB_REMOTE_WAKEUP_ENABLE) ? USB_REQ_SET_FEATURE : 7157c478bd9Sstevel@tonic-gate USB_REQ_CLEAR_FEATURE); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate if ((rval = usb_pipe_sync_ctrl_xfer(dip, ph, 7187c478bd9Sstevel@tonic-gate bmRequest, /* bmRequest */ 7197c478bd9Sstevel@tonic-gate bRequest, /* bRequest */ 7207c478bd9Sstevel@tonic-gate USB_DEV_REMOTE_WAKEUP, /* wValue */ 7217c478bd9Sstevel@tonic-gate wIndex, /* wIndex */ 7227c478bd9Sstevel@tonic-gate 0, /* wLength */ 7237c478bd9Sstevel@tonic-gate NULL, 0, 7247c478bd9Sstevel@tonic-gate &completion_reason, 7257c478bd9Sstevel@tonic-gate &cb_flags, USB_FLAGS_SLEEP)) != USB_SUCCESS) { 7267c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 7277c478bd9Sstevel@tonic-gate "Set/ClearFeature (RemoteWakep) failed: " 7287c478bd9Sstevel@tonic-gate "rval = %d, cmd = %d, cr = 0x%x cb = 0x%x", 7297c478bd9Sstevel@tonic-gate rval, cmd, completion_reason, cb_flags); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate return (rval); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate void 7377c478bd9Sstevel@tonic-gate usb_enable_parent_notification(dev_info_t *dip) 7387c478bd9Sstevel@tonic-gate { 7397c478bd9Sstevel@tonic-gate USBA_CHECK_CONTEXT(); 7407c478bd9Sstevel@tonic-gate (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 7417c478bd9Sstevel@tonic-gate "pm-want-child-notification?"); 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * usb_handle_remote_wakeup: 7477c478bd9Sstevel@tonic-gate * check if device supports remote wakeup and, if so, enable/disable 7487c478bd9Sstevel@tonic-gate * remote wake up in the device depending upon the command 7497c478bd9Sstevel@tonic-gate */ 7507c478bd9Sstevel@tonic-gate int 7517c478bd9Sstevel@tonic-gate usb_handle_remote_wakeup(dev_info_t *dip, int cmd) 7527c478bd9Sstevel@tonic-gate { 7537c478bd9Sstevel@tonic-gate usb_cfg_descr_t cfg_descr; 7547c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */ 7557c478bd9Sstevel@tonic-gate size_t cfg_length; 7567c478bd9Sstevel@tonic-gate int rval; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate USBA_CHECK_CONTEXT(); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* Obtain the raw configuration descriptor */ 7617c478bd9Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* get configuration descriptor, must succeed */ 7647c478bd9Sstevel@tonic-gate rval = usb_parse_cfg_descr(usb_cfg, cfg_length, 7657c478bd9Sstevel@tonic-gate &cfg_descr, USB_CFG_DESCR_SIZE); 7667c478bd9Sstevel@tonic-gate ASSERT(rval == USB_CFG_DESCR_SIZE); 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate /* 7697c478bd9Sstevel@tonic-gate * If the device supports remote wakeup, and PM is enabled, 7707c478bd9Sstevel@tonic-gate * we enable remote wakeup in the device 7717c478bd9Sstevel@tonic-gate */ 7727c478bd9Sstevel@tonic-gate if ((usb_is_pm_enabled(dip) == USB_SUCCESS) && 7737c478bd9Sstevel@tonic-gate (cfg_descr.bmAttributes & USB_CFG_ATTR_REMOTE_WAKEUP)) { 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate rval = usba_handle_device_remote_wakeup(dip, cmd); 7767c478bd9Sstevel@tonic-gate } else { 7777c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate return (rval); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate /* 7857c478bd9Sstevel@tonic-gate * usb_create_pm_components: 7867c478bd9Sstevel@tonic-gate * map descriptor into pm properties 7877c478bd9Sstevel@tonic-gate */ 7887c478bd9Sstevel@tonic-gate int 7897c478bd9Sstevel@tonic-gate usb_create_pm_components(dev_info_t *dip, uint_t *pwr_states) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate uchar_t *usb_cfg; /* buf for config descriptor */ 7927c478bd9Sstevel@tonic-gate usb_cfg_descr_t cfg_descr; 7937c478bd9Sstevel@tonic-gate size_t cfg_length; 7947c478bd9Sstevel@tonic-gate usba_cfg_pwr_descr_t confpwr_descr; 7957c478bd9Sstevel@tonic-gate usba_if_pwr_descr_t ifpwr_descr; 7967c478bd9Sstevel@tonic-gate uint8_t cfg_attrib; 7977c478bd9Sstevel@tonic-gate int i, lvl, rval; 7987c478bd9Sstevel@tonic-gate int n_prop = 0; 7997c478bd9Sstevel@tonic-gate uint8_t *ptr; 8007c478bd9Sstevel@tonic-gate char *drvname; 8017c478bd9Sstevel@tonic-gate char str[USBA_POWER_STR_SIZE]; 8027c478bd9Sstevel@tonic-gate char *pm_comp[USBA_N_PMCOMP]; 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate USBA_CHECK_CONTEXT(); 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (usb_is_pm_enabled(dip) != USB_SUCCESS) { 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate return (USB_FAILURE); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* Obtain the raw configuration descriptor */ 8127c478bd9Sstevel@tonic-gate usb_cfg = usb_get_raw_cfg_data(dip, &cfg_length); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* get configuration descriptor, must succceed */ 8157c478bd9Sstevel@tonic-gate rval = usb_parse_cfg_descr(usb_cfg, cfg_length, 8167c478bd9Sstevel@tonic-gate &cfg_descr, USB_CFG_DESCR_SIZE); 8177c478bd9Sstevel@tonic-gate ASSERT(rval == USB_CFG_DESCR_SIZE); 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate cfg_attrib = cfg_descr.bmAttributes; 8207c478bd9Sstevel@tonic-gate *pwr_states = 0; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * Now start creating the pm-components strings 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate drvname = (char *)ddi_driver_name(dip); 8267c478bd9Sstevel@tonic-gate (void) snprintf(str, USBA_POWER_STR_SIZE, "NAME= %s%d Power", 8277c478bd9Sstevel@tonic-gate drvname, ddi_get_instance(dip)); 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate pm_comp[n_prop] = kmem_zalloc(strlen(str) + 1, KM_SLEEP); 8307c478bd9Sstevel@tonic-gate (void) strcpy(pm_comp[n_prop++], str); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * if the device is bus powered we look at the bBusPowerSavingDx 8347c478bd9Sstevel@tonic-gate * fields else we look at bSelfPowerSavingDx fields. 8357c478bd9Sstevel@tonic-gate * OS and USB power states are numerically reversed, 8367c478bd9Sstevel@tonic-gate * 8377c478bd9Sstevel@tonic-gate * Here is the mapping :- 8387c478bd9Sstevel@tonic-gate * OS State USB State 8397c478bd9Sstevel@tonic-gate * 0 D3 (minimal or no power) 8407c478bd9Sstevel@tonic-gate * 1 D2 8417c478bd9Sstevel@tonic-gate * 2 D1 8427c478bd9Sstevel@tonic-gate * 3 D0 (Full power) 8437c478bd9Sstevel@tonic-gate * 8447c478bd9Sstevel@tonic-gate * if we own the whole device, we look at the config pwr descr 8457c478bd9Sstevel@tonic-gate * else at the interface pwr descr. 8467c478bd9Sstevel@tonic-gate */ 8477c478bd9Sstevel@tonic-gate if (usb_owns_device(dip)) { 8487c478bd9Sstevel@tonic-gate /* Parse the configuration power descriptor */ 8497c478bd9Sstevel@tonic-gate rval = usba_parse_cfg_pwr_descr(usb_cfg, cfg_length, 8507c478bd9Sstevel@tonic-gate &confpwr_descr, USBA_CFG_PWR_DESCR_SIZE); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate if (rval != USBA_CFG_PWR_DESCR_SIZE) { 8537c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 8547c478bd9Sstevel@tonic-gate "usb_create_pm_components: " 8557c478bd9Sstevel@tonic-gate "usb_parse_cfg_pwr_descr returns length of %d, " 8567c478bd9Sstevel@tonic-gate "expecting %d", rval, USBA_CFG_PWR_DESCR_SIZE); 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate return (USB_FAILURE); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate if (cfg_attrib & USB_CFG_ATTR_SELFPWR) { 8627c478bd9Sstevel@tonic-gate ptr = &confpwr_descr.bSelfPowerSavingD3; 8637c478bd9Sstevel@tonic-gate } else { 8647c478bd9Sstevel@tonic-gate ptr = &confpwr_descr.bBusPowerSavingD3; 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate } else { 8677c478bd9Sstevel@tonic-gate /* Parse the interface power descriptor */ 8687c478bd9Sstevel@tonic-gate rval = usba_parse_if_pwr_descr(usb_cfg, 8697c478bd9Sstevel@tonic-gate cfg_length, 8707c478bd9Sstevel@tonic-gate usba_get_ifno(dip), /* interface index */ 8717c478bd9Sstevel@tonic-gate 0, /* XXXX alt interface index */ 8727c478bd9Sstevel@tonic-gate &ifpwr_descr, 8737c478bd9Sstevel@tonic-gate USBA_IF_PWR_DESCR_SIZE); 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate if (rval != USBA_IF_PWR_DESCR_SIZE) { 8767c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 8777c478bd9Sstevel@tonic-gate "usb_create_pm_components: " 8787c478bd9Sstevel@tonic-gate "usb_parse_if_pwr_descr " 8797c478bd9Sstevel@tonic-gate "returns length of %d, " 8807c478bd9Sstevel@tonic-gate "expecting %d", rval, USBA_CFG_PWR_DESCR_SIZE); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate return (USB_FAILURE); 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate if (cfg_attrib & USB_CFG_ATTR_SELFPWR) { 8867c478bd9Sstevel@tonic-gate ptr = &ifpwr_descr.bSelfPowerSavingD3; 8877c478bd9Sstevel@tonic-gate } else { 8887c478bd9Sstevel@tonic-gate ptr = &ifpwr_descr.bBusPowerSavingD3; 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* walk thru levels and create prop level=name strings */ 8937c478bd9Sstevel@tonic-gate for (lvl = USB_DEV_OS_PWR_0; lvl <= USB_DEV_OS_PWR_3; lvl++) { 8947c478bd9Sstevel@tonic-gate if (*ptr || (lvl == USB_DEV_OS_PWR_3)) { 8957c478bd9Sstevel@tonic-gate (void) snprintf(str, USBA_POWER_STR_SIZE, 8967c478bd9Sstevel@tonic-gate "%d=USB D%d State", 8977c478bd9Sstevel@tonic-gate lvl, USB_DEV_OS_PWR2USB_PWR(lvl)); 8987c478bd9Sstevel@tonic-gate pm_comp[n_prop] = kmem_zalloc(strlen(str) + 1, 8997c478bd9Sstevel@tonic-gate KM_SLEEP); 9007c478bd9Sstevel@tonic-gate (void) strcpy(pm_comp[n_prop++], str); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate *pwr_states |= USB_DEV_PWRMASK(lvl); 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate ptr -= 2; /* skip to the next power state */ 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, 9097c478bd9Sstevel@tonic-gate "usb_create_pm_components: pwr_states: %x", *pwr_states); 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate /* now create the actual components */ 9127c478bd9Sstevel@tonic-gate rval = ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 9137c478bd9Sstevel@tonic-gate "pm-components", pm_comp, n_prop); 9147c478bd9Sstevel@tonic-gate if (rval == DDI_PROP_SUCCESS) { 9157c478bd9Sstevel@tonic-gate rval = USB_SUCCESS; 9167c478bd9Sstevel@tonic-gate } else { 9177c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate /* display & delete properties */ 9217c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, 9227c478bd9Sstevel@tonic-gate "usb_create_pm_components: The properties are:"); 9237c478bd9Sstevel@tonic-gate for (i = 0; i < n_prop; i++) { 9247c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, 9257c478bd9Sstevel@tonic-gate "\t%s", pm_comp[i]); 9267c478bd9Sstevel@tonic-gate kmem_free(pm_comp[i], strlen(pm_comp[i]) + 1); 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate return (rval); 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * Generic Functions to set the power level of any usb device 9357c478bd9Sstevel@tonic-gate * 9367c478bd9Sstevel@tonic-gate * Since OS and USB power states are numerically reverse, 9377c478bd9Sstevel@tonic-gate * Here is the mapping :- 9387c478bd9Sstevel@tonic-gate * OS State USB State 9397c478bd9Sstevel@tonic-gate * 0 D3 (minimal or no power) 9407c478bd9Sstevel@tonic-gate * 1 D2 9417c478bd9Sstevel@tonic-gate * 2 D1 9427c478bd9Sstevel@tonic-gate * 3 D0 (Full power) 9437c478bd9Sstevel@tonic-gate */ 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate /* set device power level to 0 (full power) */ 9467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9477c478bd9Sstevel@tonic-gate int 9487c478bd9Sstevel@tonic-gate usb_set_device_pwrlvl0(dev_info_t *dip) 9497c478bd9Sstevel@tonic-gate { 9507c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 9517c478bd9Sstevel@tonic-gate "usb_set_device_pwrlvl0 : Not Yet Implemented"); 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* set device power level to 1 */ 9587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9597c478bd9Sstevel@tonic-gate int 9607c478bd9Sstevel@tonic-gate usb_set_device_pwrlvl1(dev_info_t *dip) 9617c478bd9Sstevel@tonic-gate { 9627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 9637c478bd9Sstevel@tonic-gate "usb_set_device_pwrlvl1 : Not Yet Implemented"); 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* set device power level to 2 */ 9707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9717c478bd9Sstevel@tonic-gate int 9727c478bd9Sstevel@tonic-gate usb_set_device_pwrlvl2(dev_info_t *dip) 9737c478bd9Sstevel@tonic-gate { 9747c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 9757c478bd9Sstevel@tonic-gate "usb_set_device_pwrlvl2 : Not Yet Implemented"); 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* set device power level to 3 */ 9827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9837c478bd9Sstevel@tonic-gate int 9847c478bd9Sstevel@tonic-gate usb_set_device_pwrlvl3(dev_info_t *dip) 9857c478bd9Sstevel@tonic-gate { 9867c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 9877c478bd9Sstevel@tonic-gate "usb_set_device_pwrlvl3 : Not Yet Implemented"); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate /* 9947c478bd9Sstevel@tonic-gate * USB event management 9957c478bd9Sstevel@tonic-gate */ 9967c478bd9Sstevel@tonic-gate typedef void (*peh_t)(dev_info_t *, ddi_eventcookie_t, void *, void *); 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* 10007c478bd9Sstevel@tonic-gate * usb_register_hotplug_cbs: 10017c478bd9Sstevel@tonic-gate * Register to get callbacks for hotplug events 10027c478bd9Sstevel@tonic-gate */ 10037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10047c478bd9Sstevel@tonic-gate int 10057c478bd9Sstevel@tonic-gate usb_register_hotplug_cbs(dev_info_t *dip, 10067c478bd9Sstevel@tonic-gate int (*disconnect_event_handler)(dev_info_t *), 10077c478bd9Sstevel@tonic-gate int (*reconnect_event_handler)(dev_info_t *)) 10087c478bd9Sstevel@tonic-gate { 10097c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 10107c478bd9Sstevel@tonic-gate usba_evdata_t *evdata; 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate if ((dip == NULL) || (disconnect_event_handler == NULL) || 10137c478bd9Sstevel@tonic-gate (reconnect_event_handler == NULL)) { 10147c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 10157c478bd9Sstevel@tonic-gate "usb_register_hotplug_cbs: Bad argument(s)"); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate return (USB_FAILURE); 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 10217c478bd9Sstevel@tonic-gate "usb_register_hotplug_cbs: entry"); 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * The event list searches by ddi_get_eventcookie calls below, go 10257c478bd9Sstevel@tonic-gate * through hubd and so do not apply to host controllers. 10267c478bd9Sstevel@tonic-gate */ 10277c478bd9Sstevel@tonic-gate ASSERT(!usba_is_root_hub(dip)); 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 10307c478bd9Sstevel@tonic-gate evdata = usba_get_evdata(dip); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate if (usba_device->rm_cookie == NULL) { 10337c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT, 10347c478bd9Sstevel@tonic-gate &usba_device->rm_cookie) != DDI_SUCCESS) { 10357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 10367c478bd9Sstevel@tonic-gate "usb_register_hotplug_cbs: get rm cookie failed"); 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate goto fail; 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate if (ddi_add_event_handler(dip, usba_device->rm_cookie, 10427c478bd9Sstevel@tonic-gate (peh_t)disconnect_event_handler, 10437c478bd9Sstevel@tonic-gate NULL, &evdata->ev_rm_cb_id) != DDI_SUCCESS) { 10447c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 10457c478bd9Sstevel@tonic-gate "usb_register_hotplug_cbs: add disconnect handler failed"); 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate goto fail; 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate if (usba_device->ins_cookie == NULL) { 10517c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT, 10527c478bd9Sstevel@tonic-gate &usba_device->ins_cookie) != DDI_SUCCESS) { 10537c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 10547c478bd9Sstevel@tonic-gate "usb_register_hotplug_cbs: get ins cookie failed"); 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate goto fail; 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate if (ddi_add_event_handler(dip, usba_device->ins_cookie, 10607c478bd9Sstevel@tonic-gate (peh_t)reconnect_event_handler, 10617c478bd9Sstevel@tonic-gate NULL, &evdata->ev_ins_cb_id) != DDI_SUCCESS) { 10627c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 10637c478bd9Sstevel@tonic-gate "usb_register_hotplug_cbs: add reconnect handler failed"); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate goto fail; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 10697c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |= 10707c478bd9Sstevel@tonic-gate USBA_CLIENT_FLAG_EV_CBS; 10717c478bd9Sstevel@tonic-gate usba_device->usb_client_ev_cb_list->dip = dip; 10727c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate fail: 10777c478bd9Sstevel@tonic-gate usb_unregister_hotplug_cbs(dip); 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate return (USB_FAILURE); 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate /* 10857c478bd9Sstevel@tonic-gate * usb_unregister_hotplug_cbs: 10867c478bd9Sstevel@tonic-gate * Unregister hotplug callbacks 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10897c478bd9Sstevel@tonic-gate void 10907c478bd9Sstevel@tonic-gate usb_unregister_hotplug_cbs(dev_info_t *dip) 10917c478bd9Sstevel@tonic-gate { 10927c478bd9Sstevel@tonic-gate usb_unregister_event_cbs(dip, NULL); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * usb_register_event_cbs: 10987c478bd9Sstevel@tonic-gate * Register to get callbacks for USB events 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11017c478bd9Sstevel@tonic-gate int 11027c478bd9Sstevel@tonic-gate usb_register_event_cbs(dev_info_t *dip, usb_event_t *usb_evdata, 11037c478bd9Sstevel@tonic-gate usb_flags_t flags) 11047c478bd9Sstevel@tonic-gate { 11057c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 11067c478bd9Sstevel@tonic-gate usba_evdata_t *evdata; 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate if ((dip == NULL) || (usb_evdata == NULL)) { 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate return (USB_FAILURE); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate /* 11147c478bd9Sstevel@tonic-gate * The event list searches by ddi_get_eventcookie calls below, go 11157c478bd9Sstevel@tonic-gate * through hubd and so do not apply to host controllers. 11167c478bd9Sstevel@tonic-gate */ 11177c478bd9Sstevel@tonic-gate ASSERT(!usba_is_root_hub(dip)); 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 11207c478bd9Sstevel@tonic-gate evdata = usba_get_evdata(dip); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate if (usb_evdata->disconnect_event_handler != NULL) { 11237c478bd9Sstevel@tonic-gate if (usba_device->rm_cookie == NULL) { 11247c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dip, DDI_DEVI_REMOVE_EVENT, 11257c478bd9Sstevel@tonic-gate &usba_device->rm_cookie) != DDI_SUCCESS) { 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate goto fail; 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate if (ddi_add_event_handler(dip, usba_device->rm_cookie, 11317c478bd9Sstevel@tonic-gate (peh_t)usb_evdata->disconnect_event_handler, 11327c478bd9Sstevel@tonic-gate NULL, &evdata->ev_rm_cb_id) != DDI_SUCCESS) { 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate goto fail; 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate if (usb_evdata->reconnect_event_handler != NULL) { 11387c478bd9Sstevel@tonic-gate if (usba_device->ins_cookie == NULL) { 11397c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dip, DDI_DEVI_INSERT_EVENT, 11407c478bd9Sstevel@tonic-gate &usba_device->ins_cookie) != DDI_SUCCESS) { 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate goto fail; 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate if (ddi_add_event_handler(dip, usba_device->ins_cookie, 11467c478bd9Sstevel@tonic-gate (peh_t)usb_evdata->reconnect_event_handler, 11477c478bd9Sstevel@tonic-gate NULL, &evdata->ev_ins_cb_id) != DDI_SUCCESS) { 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate goto fail; 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate if (usb_evdata->post_resume_event_handler != NULL) { 11537c478bd9Sstevel@tonic-gate if (usba_device->resume_cookie == NULL) { 11547c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dip, USBA_POST_RESUME_EVENT, 11557c478bd9Sstevel@tonic-gate &usba_device->resume_cookie) != DDI_SUCCESS) { 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate goto fail; 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate if (ddi_add_event_handler(dip, usba_device->resume_cookie, 11617c478bd9Sstevel@tonic-gate (peh_t)usb_evdata->post_resume_event_handler, 11627c478bd9Sstevel@tonic-gate NULL, &evdata->ev_resume_cb_id) != DDI_SUCCESS) { 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate goto fail; 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate if (usb_evdata->pre_suspend_event_handler != NULL) { 11687c478bd9Sstevel@tonic-gate if (usba_device->suspend_cookie == NULL) { 11697c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dip, USBA_PRE_SUSPEND_EVENT, 11707c478bd9Sstevel@tonic-gate &usba_device->suspend_cookie) != DDI_SUCCESS) { 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate goto fail; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate if (ddi_add_event_handler(dip, usba_device->suspend_cookie, 11767c478bd9Sstevel@tonic-gate (peh_t)usb_evdata->pre_suspend_event_handler, 11777c478bd9Sstevel@tonic-gate NULL, &evdata->ev_suspend_cb_id) != DDI_SUCCESS) { 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate goto fail; 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate 11837c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 11847c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] |= 11857c478bd9Sstevel@tonic-gate USBA_CLIENT_FLAG_EV_CBS; 11867c478bd9Sstevel@tonic-gate usba_device->usb_client_ev_cb_list->dip = dip; 11877c478bd9Sstevel@tonic-gate usba_device->usb_client_ev_cb_list->ev_data = usb_evdata; 11887c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate fail: 11937c478bd9Sstevel@tonic-gate usb_unregister_event_cbs(dip, usb_evdata); 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate return (USB_FAILURE); 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * usb_unregister_event_cbs: 12027c478bd9Sstevel@tonic-gate * Unregister all event callbacks 12037c478bd9Sstevel@tonic-gate */ 12047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12057c478bd9Sstevel@tonic-gate void 12067c478bd9Sstevel@tonic-gate usb_unregister_event_cbs(dev_info_t *dip, usb_event_t *usb_evdata) 12077c478bd9Sstevel@tonic-gate { 12087c478bd9Sstevel@tonic-gate usba_evdata_t *evdata; 12097c478bd9Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip); 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate evdata = usba_get_evdata(dip); 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate if (evdata->ev_rm_cb_id != NULL) { 12147c478bd9Sstevel@tonic-gate (void) ddi_remove_event_handler(evdata->ev_rm_cb_id); 12157c478bd9Sstevel@tonic-gate evdata->ev_rm_cb_id = NULL; 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate if (evdata->ev_ins_cb_id != NULL) { 12197c478bd9Sstevel@tonic-gate (void) ddi_remove_event_handler(evdata->ev_ins_cb_id); 12207c478bd9Sstevel@tonic-gate evdata->ev_ins_cb_id = NULL; 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate if (evdata->ev_suspend_cb_id != NULL) { 12247c478bd9Sstevel@tonic-gate (void) ddi_remove_event_handler(evdata->ev_suspend_cb_id); 12257c478bd9Sstevel@tonic-gate evdata->ev_suspend_cb_id = NULL; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate if (evdata->ev_resume_cb_id != NULL) { 12297c478bd9Sstevel@tonic-gate (void) ddi_remove_event_handler(evdata->ev_resume_cb_id); 12307c478bd9Sstevel@tonic-gate evdata->ev_resume_cb_id = NULL; 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 12347c478bd9Sstevel@tonic-gate usba_device->usb_client_flags[usba_get_ifno(dip)] &= 12357c478bd9Sstevel@tonic-gate ~USBA_CLIENT_FLAG_EV_CBS; 12367c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 12377c478bd9Sstevel@tonic-gate } 1238ffcd51f3Slg150142 1239ffcd51f3Slg150142 int 1240ffcd51f3Slg150142 usb_reset_device(dev_info_t *dip, usb_dev_reset_lvl_t reset_level) 1241ffcd51f3Slg150142 { 1242ffcd51f3Slg150142 return (usba_hubdi_reset_device(dip, reset_level)); 1243ffcd51f3Slg150142 } 1244a7df97baSStrony Zhang - Solaris China Team 1245a7df97baSStrony Zhang - Solaris China Team /* 1246a7df97baSStrony Zhang - Solaris China Team * usb device driver registration 1247a7df97baSStrony Zhang - Solaris China Team */ 1248a7df97baSStrony Zhang - Solaris China Team int 1249a7df97baSStrony Zhang - Solaris China Team usb_register_dev_driver(dev_info_t *dip, usb_dev_driver_callback_t cb) 1250a7df97baSStrony Zhang - Solaris China Team { 1251a7df97baSStrony Zhang - Solaris China Team USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1252a7df97baSStrony Zhang - Solaris China Team "usb_register_dev_driver: register the specified driver " 1253a7df97baSStrony Zhang - Solaris China Team "in usba: dip = 0x%p", (void *)dip); 1254a7df97baSStrony Zhang - Solaris China Team 1255a7df97baSStrony Zhang - Solaris China Team if (cb != NULL) { 1256a7df97baSStrony Zhang - Solaris China Team usb_cap.dip = dip; 1257a7df97baSStrony Zhang - Solaris China Team usb_cap.usba_dev_driver_cb = cb; 1258a7df97baSStrony Zhang - Solaris China Team 1259a7df97baSStrony Zhang - Solaris China Team return (USB_SUCCESS); 1260a7df97baSStrony Zhang - Solaris China Team } 1261a7df97baSStrony Zhang - Solaris China Team 1262a7df97baSStrony Zhang - Solaris China Team return (USB_FAILURE); 1263a7df97baSStrony Zhang - Solaris China Team } 1264a7df97baSStrony Zhang - Solaris China Team 1265a7df97baSStrony Zhang - Solaris China Team /* 1266a7df97baSStrony Zhang - Solaris China Team * usb device driver unregistration 1267a7df97baSStrony Zhang - Solaris China Team */ 1268a7df97baSStrony Zhang - Solaris China Team void 1269a7df97baSStrony Zhang - Solaris China Team usb_unregister_dev_driver(dev_info_t *dip) 1270a7df97baSStrony Zhang - Solaris China Team { 1271a7df97baSStrony Zhang - Solaris China Team USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1272a7df97baSStrony Zhang - Solaris China Team "usb_unregister_dev_driver: unregister the registered " 1273a7df97baSStrony Zhang - Solaris China Team "driver: dip =0x%p", (void *)dip); 1274a7df97baSStrony Zhang - Solaris China Team 1275a7df97baSStrony Zhang - Solaris China Team ASSERT(dip == usb_cap.dip); 1276a7df97baSStrony Zhang - Solaris China Team usb_cap.dip = NULL; 1277a7df97baSStrony Zhang - Solaris China Team usb_cap.usba_dev_driver_cb = NULL; 1278a7df97baSStrony Zhang - Solaris China Team } 1279