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