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