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