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