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