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