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