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 * UGEN: USB Generic Driver support code 30 * 31 * This code provides entry points called by the ugen driver or other 32 * drivers that want to export a ugen interface 33 * 34 * The "Universal Generic Driver" (UGEN) for USB devices provides interfaces 35 * to talk to USB devices. This is very useful for Point of Sale sale 36 * devices and other simple devices like USB scanner, USB palm pilot. 37 * The UGEN provides a system call interface to USB devices enabling 38 * a USB device vendor to write an application for his 39 * device instead of writing a driver. This facilitates the vendor to write 40 * device management s/w quickly in userland. 41 * 42 * UGEN supports read/write/poll entry points. An application can be written 43 * using read/write/aioread/aiowrite/poll system calls to communicate 44 * with the device. 45 * 46 * XXX Theory of Operations 47 */ 48 #include <sys/usb/usba/usbai_version.h> 49 #include <sys/usb/usba.h> 50 #include <sys/sysmacros.h> 51 52 #include "sys/usb/clients/ugen/usb_ugen.h" 53 #include "sys/usb/usba/usba_ugen.h" 54 #include "sys/usb/usba/usba_ugend.h" 55 56 /* Debugging information */ 57 static uint_t ugen_errmask = (uint_t)UGEN_PRINT_ALL; 58 static uint_t ugen_errlevel = USB_LOG_L4; 59 static uint_t ugen_instance_debug = (uint_t)-1; 60 61 /* default endpoint descriptor */ 62 static usb_ep_descr_t ugen_default_ep_descr = 63 {7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0}; 64 65 /* tunables */ 66 static int ugen_busy_loop = 60; /* secs */ 67 static int ugen_ctrl_timeout = 10; 68 static int ugen_bulk_timeout = 10; 69 static int ugen_intr_timeout = 10; 70 static int ugen_enable_pm = 0; 71 72 73 /* local function prototypes */ 74 static int ugen_cleanup(ugen_state_t *); 75 static int ugen_cpr_suspend(ugen_state_t *); 76 static void ugen_cpr_resume(ugen_state_t *); 77 78 static void ugen_restore_state(ugen_state_t *); 79 static int ugen_check_open_flags(ugen_state_t *, dev_t, int); 80 static int ugen_strategy(struct buf *); 81 static void ugen_minphys(struct buf *); 82 83 static void ugen_pm_init(ugen_state_t *); 84 static void ugen_pm_destroy(ugen_state_t *); 85 static void ugen_pm_busy_component(ugen_state_t *); 86 static void ugen_pm_idle_component(ugen_state_t *); 87 88 /* endpoint xfer and status management */ 89 static int ugen_epxs_init(ugen_state_t *); 90 static void ugen_epxs_destroy(ugen_state_t *); 91 static int ugen_epxs_data_init(ugen_state_t *, usb_ep_data_t *, 92 uchar_t, uchar_t, uchar_t, uchar_t); 93 static void ugen_epxs_data_destroy(ugen_state_t *, ugen_ep_t *); 94 static int ugen_epxs_minor_nodes_create(ugen_state_t *, 95 usb_ep_descr_t *, uchar_t, 96 uchar_t, uchar_t, uchar_t); 97 static int ugen_epxs_check_open_nodes(ugen_state_t *); 98 99 static int ugen_epx_open(ugen_state_t *, dev_t, int); 100 static void ugen_epx_close(ugen_state_t *, dev_t, int); 101 static void ugen_epx_shutdown(ugen_state_t *); 102 103 static int ugen_epx_open_pipe(ugen_state_t *, ugen_ep_t *, int); 104 static void ugen_epx_close_pipe(ugen_state_t *, ugen_ep_t *); 105 106 static int ugen_epx_req(ugen_state_t *, struct buf *); 107 static int ugen_epx_ctrl_req(ugen_state_t *, ugen_ep_t *, 108 struct buf *, boolean_t *); 109 static void ugen_epx_ctrl_req_cb(usb_pipe_handle_t, usb_ctrl_req_t *); 110 static int ugen_epx_bulk_req(ugen_state_t *, ugen_ep_t *, 111 struct buf *, boolean_t *); 112 static void ugen_epx_bulk_req_cb(usb_pipe_handle_t, usb_bulk_req_t *); 113 static int ugen_epx_intr_IN_req(ugen_state_t *, ugen_ep_t *, 114 struct buf *, boolean_t *); 115 static int ugen_epx_intr_IN_start_polling(ugen_state_t *, ugen_ep_t *); 116 static void ugen_epx_intr_IN_stop_polling(ugen_state_t *, ugen_ep_t *); 117 static void ugen_epx_intr_IN_req_cb(usb_pipe_handle_t, usb_intr_req_t *); 118 static int ugen_epx_intr_OUT_req(ugen_state_t *, ugen_ep_t *, 119 struct buf *, boolean_t *); 120 static void ugen_epx_intr_OUT_req_cb(usb_pipe_handle_t, usb_intr_req_t *); 121 122 static int ugen_eps_open(ugen_state_t *, dev_t, int); 123 static void ugen_eps_close(ugen_state_t *, dev_t, int); 124 static int ugen_eps_req(ugen_state_t *, struct buf *); 125 static void ugen_update_ep_descr(ugen_state_t *, ugen_ep_t *); 126 127 /* device status management */ 128 static int ugen_ds_init(ugen_state_t *); 129 static void ugen_ds_destroy(ugen_state_t *); 130 static int ugen_ds_open(ugen_state_t *, dev_t, int); 131 static void ugen_ds_close(ugen_state_t *, dev_t, int); 132 static int ugen_ds_req(ugen_state_t *, struct buf *); 133 static void ugen_ds_change(ugen_state_t *); 134 static int ugen_ds_minor_nodes_create(ugen_state_t *); 135 static void ugen_ds_poll_wakeup(ugen_state_t *); 136 137 /* utility functions */ 138 static int ugen_minor_index_create(ugen_state_t *, ugen_minor_t); 139 static ugen_minor_t ugen_devt2minor(ugen_state_t *, dev_t); 140 static void ugen_minor_node_table_create(ugen_state_t *); 141 static void ugen_minor_node_table_destroy(ugen_state_t *); 142 static void ugen_minor_node_table_shrink(ugen_state_t *); 143 static int ugen_cr2lcstat(int); 144 static void ugen_check_mask(uint_t, uint_t *, uint_t *); 145 static int ugen_is_valid_minor_node(ugen_state_t *, dev_t); 146 147 static kmutex_t ugen_devt_list_mutex; 148 static ugen_devt_list_entry_t ugen_devt_list; 149 static ugen_devt_cache_entry_t ugen_devt_cache[UGEN_DEVT_CACHE_SIZE]; 150 static uint_t ugen_devt_cache_index; 151 static void ugen_store_devt(ugen_state_t *, minor_t); 152 static ugen_state_t *ugen_devt2state(dev_t); 153 static void ugen_free_devt(ugen_state_t *); 154 155 /* 156 * usb_ugen entry points 157 * 158 * usb_ugen_get_hdl: 159 * allocate and initialize handle 160 */ 161 usb_ugen_hdl_t 162 usb_ugen_get_hdl(dev_info_t *dip, usb_ugen_info_t *usb_ugen_info) 163 { 164 usb_ugen_hdl_impl_t *hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP); 165 ugen_state_t *ugenp = kmem_zalloc(sizeof (ugen_state_t), 166 KM_SLEEP); 167 uint_t len, shift, limit; 168 int rval; 169 170 hdl->hdl_ugenp = ugenp; 171 172 /* masks may not overlap */ 173 if (usb_ugen_info->usb_ugen_minor_node_ugen_bits_mask & 174 usb_ugen_info->usb_ugen_minor_node_instance_mask) { 175 usb_ugen_release_hdl((usb_ugen_hdl_t)hdl); 176 177 return (NULL); 178 } 179 180 if ((rval = usb_get_dev_data(dip, &ugenp->ug_dev_data, 181 usb_owns_device(dip) ? USB_PARSE_LVL_ALL : USB_PARSE_LVL_IF, 182 0)) != USB_SUCCESS) { 183 USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 184 "usb_ugen_attach: usb_get_dev_data failed, rval=%d", rval); 185 186 return (NULL); 187 } 188 189 /* Initialize state structure for this instance */ 190 mutex_init(&ugenp->ug_mutex, NULL, MUTEX_DRIVER, 191 ugenp->ug_dev_data->dev_iblock_cookie); 192 193 mutex_enter(&ugenp->ug_mutex); 194 ugenp->ug_dip = dip; 195 ugenp->ug_instance = ddi_get_instance(dip); 196 ugenp->ug_hdl = hdl; 197 198 /* Allocate a log handle for debug/error messages */ 199 if (strcmp(ddi_driver_name(dip), "ugen") != 0) { 200 char *name; 201 202 len = strlen(ddi_driver_name(dip)) + sizeof ("_ugen") + 1; 203 name = kmem_alloc(len, KM_SLEEP); 204 (void) snprintf(name, len, "%s_ugen", ddi_driver_name(dip)); 205 206 ugenp->ug_log_hdl = usb_alloc_log_hdl(dip, name, &ugen_errlevel, 207 &ugen_errmask, &ugen_instance_debug, 0); 208 hdl->hdl_log_name = name; 209 hdl->hdl_log_name_length = len; 210 } else { 211 ugenp->ug_log_hdl = usb_alloc_log_hdl(dip, "ugen", 212 &ugen_errlevel, 213 &ugen_errmask, &ugen_instance_debug, 0); 214 } 215 216 hdl->hdl_dip = dip; 217 hdl->hdl_flags = usb_ugen_info->usb_ugen_flags; 218 219 ugen_check_mask(usb_ugen_info->usb_ugen_minor_node_ugen_bits_mask, 220 &shift, &limit); 221 if (limit == 0) { 222 usb_ugen_release_hdl((usb_ugen_hdl_t)hdl); 223 mutex_exit(&ugenp->ug_mutex); 224 225 return (NULL); 226 } 227 hdl->hdl_minor_node_ugen_bits_mask = usb_ugen_info-> 228 usb_ugen_minor_node_ugen_bits_mask; 229 hdl->hdl_minor_node_ugen_bits_shift = shift; 230 hdl->hdl_minor_node_ugen_bits_limit = limit; 231 232 ugen_check_mask(usb_ugen_info->usb_ugen_minor_node_instance_mask, 233 &shift, &limit); 234 if (limit == 0) { 235 usb_ugen_release_hdl((usb_ugen_hdl_t)hdl); 236 mutex_exit(&ugenp->ug_mutex); 237 238 return (NULL); 239 } 240 241 hdl->hdl_minor_node_instance_mask = usb_ugen_info-> 242 usb_ugen_minor_node_instance_mask; 243 hdl->hdl_minor_node_instance_shift = shift; 244 hdl->hdl_minor_node_instance_limit = limit; 245 246 USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 247 "usb_ugen_get_hdl: instance shift=%d instance limit=%d", 248 hdl->hdl_minor_node_instance_shift, 249 hdl->hdl_minor_node_instance_limit); 250 251 USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 252 "usb_ugen_get_hdl: bits shift=%d bits limit=%d", 253 hdl->hdl_minor_node_ugen_bits_shift, 254 hdl->hdl_minor_node_ugen_bits_limit); 255 256 mutex_exit(&ugenp->ug_mutex); 257 258 return ((usb_ugen_hdl_t)hdl); 259 } 260 261 262 /* 263 * usb_ugen_release_hdl: 264 * deallocate a handle 265 */ 266 void 267 usb_ugen_release_hdl(usb_ugen_hdl_t usb_ugen_hdl) 268 { 269 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 270 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 271 272 if (usb_ugen_hdl_impl) { 273 ugen_state_t *ugenp = usb_ugen_hdl_impl->hdl_ugenp; 274 275 if (ugenp) { 276 mutex_destroy(&ugenp->ug_mutex); 277 usb_free_log_hdl(ugenp->ug_log_hdl); 278 usb_free_dev_data(usb_ugen_hdl_impl->hdl_dip, 279 ugenp->ug_dev_data); 280 kmem_free(ugenp, sizeof (*ugenp)); 281 } 282 if (usb_ugen_hdl_impl->hdl_log_name) { 283 kmem_free(usb_ugen_hdl_impl->hdl_log_name, 284 usb_ugen_hdl_impl->hdl_log_name_length); 285 } 286 kmem_free(usb_ugen_hdl_impl, sizeof (*usb_ugen_hdl_impl)); 287 } 288 } 289 290 291 /* 292 * usb_ugen_attach() 293 */ 294 int 295 usb_ugen_attach(usb_ugen_hdl_t usb_ugen_hdl, ddi_attach_cmd_t cmd) 296 { 297 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 298 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 299 ugen_state_t *ugenp; 300 dev_info_t *dip; 301 302 if (usb_ugen_hdl == NULL) { 303 304 return (USB_FAILURE); 305 } 306 307 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 308 dip = usb_ugen_hdl_impl->hdl_dip; 309 310 311 USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 312 "usb_ugen_attach: cmd=%d", cmd); 313 314 switch (cmd) { 315 case DDI_ATTACH: 316 317 break; 318 case DDI_RESUME: 319 ugen_cpr_resume(ugenp); 320 321 return (USB_SUCCESS); 322 default: 323 USB_DPRINTF_L2(UGEN_PRINT_ATTA, NULL, 324 "usb_ugen_attach: unknown command"); 325 326 return (USB_FAILURE); 327 } 328 329 mutex_enter(&ugenp->ug_mutex); 330 ugenp->ug_ser_cookie = 331 usb_init_serialization(dip, USB_INIT_SER_CHECK_SAME_THREAD); 332 ugenp->ug_cleanup_flags |= UGEN_INIT_LOCKS; 333 334 /* Get maximum bulk transfer size supported by the HCD */ 335 if (usb_pipe_get_max_bulk_transfer_size(dip, 336 &ugenp->ug_max_bulk_xfer_sz) != USB_SUCCESS) { 337 USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 338 "usb_ugen_attach: Getting max bulk xfer sz failed"); 339 mutex_exit(&ugenp->ug_mutex); 340 341 goto fail; 342 } 343 344 /* table for mapping 48 bit minor codes to 9 bit index (for ugen) */ 345 ugen_minor_node_table_create(ugenp); 346 347 /* prepare device status node handling */ 348 if (ugen_ds_init(ugenp) != USB_SUCCESS) { 349 USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 350 "usb_ugen_attach: preparing dev status failed"); 351 mutex_exit(&ugenp->ug_mutex); 352 353 goto fail; 354 } 355 356 /* prepare all available xfer and status endpoints nodes */ 357 if (ugen_epxs_init(ugenp) != USB_SUCCESS) { 358 USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 359 "usb_ugen_attach: preparing endpoints failed"); 360 mutex_exit(&ugenp->ug_mutex); 361 362 goto fail; 363 } 364 365 /* reduce table size if not all entries are used */ 366 ugen_minor_node_table_shrink(ugenp); 367 368 /* we are ready to go */ 369 ugenp->ug_dev_state = USB_DEV_ONLINE; 370 371 mutex_exit(&ugenp->ug_mutex); 372 373 /* prepare PM */ 374 if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 375 ugen_pm_init(ugenp); 376 } 377 378 /* 379 * if ugen driver, kill all child nodes otherwise set cfg fails 380 * if requested 381 */ 382 if (usb_owns_device(dip) && 383 (usb_ugen_hdl_impl->hdl_flags & USB_UGEN_REMOVE_CHILDREN)) { 384 dev_info_t *cdip; 385 386 /* save cfgidx so we can restore on detach */ 387 mutex_enter(&ugenp->ug_mutex); 388 ugenp->ug_initial_cfgidx = usb_get_current_cfgidx(dip); 389 mutex_exit(&ugenp->ug_mutex); 390 391 for (cdip = ddi_get_child(dip); cdip; ) { 392 dev_info_t *next = ddi_get_next_sibling(cdip); 393 (void) ddi_remove_child(cdip, 0); 394 cdip = next; 395 } 396 } 397 398 return (DDI_SUCCESS); 399 fail: 400 if (ugenp) { 401 USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 402 "attach fail"); 403 (void) ugen_cleanup(ugenp); 404 } 405 406 return (DDI_FAILURE); 407 } 408 409 410 /* 411 * usb_ugen_detach() 412 */ 413 int 414 usb_ugen_detach(usb_ugen_hdl_t usb_ugen_hdl, ddi_detach_cmd_t cmd) 415 { 416 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 417 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 418 int rval = USB_FAILURE; 419 420 if (usb_ugen_hdl) { 421 ugen_state_t *ugenp = usb_ugen_hdl_impl->hdl_ugenp; 422 423 USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 424 "usb_ugen_detach cmd %d", cmd); 425 426 switch (cmd) { 427 case DDI_DETACH: 428 rval = ugen_cleanup(ugenp); 429 430 break; 431 case DDI_SUSPEND: 432 rval = ugen_cpr_suspend(ugenp); 433 434 break; 435 default: 436 437 break; 438 } 439 } 440 441 return (rval); 442 } 443 444 445 /* 446 * ugen_cleanup() 447 */ 448 static int 449 ugen_cleanup(ugen_state_t *ugenp) 450 { 451 dev_info_t *dip = ugenp->ug_dip; 452 453 USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, "ugen_cleanup"); 454 455 if (ugenp->ug_cleanup_flags & UGEN_INIT_LOCKS) { 456 457 /* shutdown all endpoints */ 458 ugen_epx_shutdown(ugenp); 459 460 /* 461 * At this point, no new activity can be initiated. 462 * The driver has disabled hotplug callbacks. 463 * The Solaris framework has disabled 464 * new opens on a device being detached, and does not 465 * allow detaching an open device. PM should power 466 * down while we are detaching 467 * 468 * The following ensures that any other driver 469 * activity must have drained (paranoia) 470 */ 471 (void) usb_serialize_access(ugenp->ug_ser_cookie, 472 USB_WAIT, 0); 473 usb_release_access(ugenp->ug_ser_cookie); 474 475 mutex_enter(&ugenp->ug_mutex); 476 ASSERT(ugenp->ug_open_count == 0); 477 ASSERT(ugenp->ug_pending_cmds == 0); 478 479 /* dismantle in reverse order */ 480 ugen_pm_destroy(ugenp); 481 ugen_epxs_destroy(ugenp); 482 ugen_ds_destroy(ugenp); 483 ugen_minor_node_table_destroy(ugenp); 484 485 486 /* restore to initial configuration */ 487 if (usb_owns_device(dip) && 488 (ugenp->ug_dev_state != USB_DEV_DISCONNECTED)) { 489 int idx = ugenp->ug_initial_cfgidx; 490 mutex_exit(&ugenp->ug_mutex); 491 (void) usb_set_cfg(dip, idx, 492 USB_FLAGS_SLEEP, NULL, NULL); 493 } else { 494 mutex_exit(&ugenp->ug_mutex); 495 } 496 497 usb_fini_serialization(ugenp->ug_ser_cookie); 498 } 499 500 ddi_prop_remove_all(dip); 501 ddi_remove_minor_node(dip, NULL); 502 503 ugen_free_devt(ugenp); 504 505 return (USB_SUCCESS); 506 } 507 508 509 /* 510 * ugen_cpr_suspend 511 */ 512 static int 513 ugen_cpr_suspend(ugen_state_t *ugenp) 514 { 515 int rval = USB_FAILURE; 516 int i; 517 int prev_state; 518 519 USB_DPRINTF_L4(UGEN_PRINT_CPR, ugenp->ug_log_hdl, 520 "ugen_cpr_suspend:"); 521 522 mutex_enter(&ugenp->ug_mutex); 523 switch (ugenp->ug_dev_state) { 524 case USB_DEV_ONLINE: 525 case USB_DEV_DISCONNECTED: 526 USB_DPRINTF_L4(UGEN_PRINT_CPR, ugenp->ug_log_hdl, 527 "ugen_cpr_suspend:"); 528 529 prev_state = ugenp->ug_dev_state; 530 ugenp->ug_dev_state = USB_DEV_SUSPENDED; 531 532 if (ugenp->ug_open_count) { 533 /* drain outstanding cmds */ 534 for (i = 0; i < ugen_busy_loop; i++) { 535 if (ugenp->ug_pending_cmds == 0) { 536 537 break; 538 } 539 mutex_exit(&ugenp->ug_mutex); 540 delay(drv_usectohz(100000)); 541 mutex_enter(&ugenp->ug_mutex); 542 } 543 544 /* if still outstanding cmds, fail suspend */ 545 if (ugenp->ug_pending_cmds) { 546 ugenp->ug_dev_state = prev_state; 547 548 USB_DPRINTF_L2(UGEN_PRINT_CPR, 549 ugenp->ug_log_hdl, 550 "ugen_cpr_suspend: pending %d", 551 ugenp->ug_pending_cmds); 552 553 rval = USB_FAILURE; 554 break; 555 } 556 557 mutex_exit(&ugenp->ug_mutex); 558 (void) usb_serialize_access(ugenp->ug_ser_cookie, 559 USB_WAIT, 0); 560 /* close all pipes */ 561 ugen_epx_shutdown(ugenp); 562 563 usb_release_access(ugenp->ug_ser_cookie); 564 565 mutex_enter(&ugenp->ug_mutex); 566 } 567 568 /* wakeup devstat reads and polls */ 569 ugen_ds_change(ugenp); 570 ugen_ds_poll_wakeup(ugenp); 571 572 rval = USB_SUCCESS; 573 break; 574 case USB_DEV_SUSPENDED: 575 case USB_UGEN_DEV_UNAVAILABLE_RESUME: 576 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 577 default: 578 579 break; 580 } 581 mutex_exit(&ugenp->ug_mutex); 582 583 return (rval); 584 } 585 586 /* 587 * ugen_cpr_resume 588 */ 589 static void 590 ugen_cpr_resume(ugen_state_t *ugenp) 591 { 592 USB_DPRINTF_L4(UGEN_PRINT_CPR, ugenp->ug_log_hdl, 593 "ugen_cpr_resume:"); 594 595 ugen_restore_state(ugenp); 596 } 597 598 /* 599 * usb_ugen_disconnect_ev_cb: 600 */ 601 int 602 usb_ugen_disconnect_ev_cb(usb_ugen_hdl_t usb_ugen_hdl) 603 { 604 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 605 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 606 ugen_state_t *ugenp; 607 608 if (usb_ugen_hdl_impl == NULL) { 609 610 return (USB_FAILURE); 611 } 612 613 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 614 615 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 616 "usb_ugen_disconnect_ev_cb:"); 617 618 /* get exclusive access */ 619 (void) usb_serialize_access(ugenp->ug_ser_cookie, USB_WAIT, 0); 620 621 mutex_enter(&ugenp->ug_mutex); 622 ugenp->ug_dev_state = USB_DEV_DISCONNECTED; 623 if (ugenp->ug_open_count) { 624 mutex_exit(&ugenp->ug_mutex); 625 626 /* close all pipes */ 627 (void) ugen_epx_shutdown(ugenp); 628 629 mutex_enter(&ugenp->ug_mutex); 630 } 631 632 633 /* wakeup devstat reads and polls */ 634 ugen_ds_change(ugenp); 635 ugen_ds_poll_wakeup(ugenp); 636 637 mutex_exit(&ugenp->ug_mutex); 638 usb_release_access(ugenp->ug_ser_cookie); 639 640 return (USB_SUCCESS); 641 } 642 643 644 /* 645 * usb_ugen_reconnect_ev_cb: 646 */ 647 int 648 usb_ugen_reconnect_ev_cb(usb_ugen_hdl_t usb_ugen_hdl) 649 { 650 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 651 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 652 ugen_state_t *ugenp = usb_ugen_hdl_impl->hdl_ugenp; 653 654 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 655 "usb_ugen_reconnect_ev_cb:"); 656 657 ugen_restore_state(ugenp); 658 659 return (USB_SUCCESS); 660 } 661 662 663 /* 664 * ugen_restore_state: 665 * Check for same device; if a different device is attached, set 666 * the device status to disconnected. 667 * If we were open, then set to UNAVAILABLE until all endpoints have 668 * be closed. 669 */ 670 static void 671 ugen_restore_state(ugen_state_t *ugenp) 672 { 673 dev_info_t *dip = ugenp->ug_dip; 674 675 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 676 "ugen_restore_state"); 677 678 /* first raise power */ 679 if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 680 ugen_pm_busy_component(ugenp); 681 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 682 } 683 684 /* Check if we are talking to the same device */ 685 if (usb_check_same_device(dip, ugenp->ug_log_hdl, 686 USB_LOG_L0, UGEN_PRINT_HOTPLUG, USB_CHK_ALL, NULL) == 687 USB_FAILURE) { 688 mutex_enter(&ugenp->ug_mutex); 689 ugenp->ug_dev_state = USB_DEV_DISCONNECTED; 690 691 /* wakeup devstat reads and polls */ 692 ugen_ds_change(ugenp); 693 ugen_ds_poll_wakeup(ugenp); 694 695 mutex_exit(&ugenp->ug_mutex); 696 697 if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 698 ugen_pm_idle_component(ugenp); 699 } 700 701 return; 702 } 703 704 /* 705 * get exclusive access, we don't want to change state in the 706 * middle of some other actions 707 */ 708 (void) usb_serialize_access(ugenp->ug_ser_cookie, USB_WAIT, 0); 709 710 mutex_enter(&ugenp->ug_mutex); 711 switch (ugenp->ug_dev_state) { 712 case USB_DEV_DISCONNECTED: 713 ugenp->ug_dev_state = (ugenp->ug_open_count == 0) ? 714 USB_DEV_ONLINE : USB_UGEN_DEV_UNAVAILABLE_RECONNECT; 715 716 break; 717 case USB_DEV_SUSPENDED: 718 ugenp->ug_dev_state = (ugenp->ug_open_count == 0) ? 719 USB_DEV_ONLINE : USB_UGEN_DEV_UNAVAILABLE_RESUME; 720 721 break; 722 } 723 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG, ugenp->ug_log_hdl, 724 "ugen_restore_state: state=%d, opencount=%d", 725 ugenp->ug_dev_state, ugenp->ug_open_count); 726 727 /* wakeup devstat reads and polls */ 728 ugen_ds_change(ugenp); 729 ugen_ds_poll_wakeup(ugenp); 730 731 mutex_exit(&ugenp->ug_mutex); 732 usb_release_access(ugenp->ug_ser_cookie); 733 734 if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 735 ugen_pm_idle_component(ugenp); 736 } 737 } 738 739 740 /* 741 * usb_ugen_open: 742 */ 743 /* ARGSUSED */ 744 int 745 usb_ugen_open(usb_ugen_hdl_t usb_ugen_hdl, dev_t *devp, int flag, int sflag, 746 cred_t *cr) 747 { 748 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 749 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 750 ugen_state_t *ugenp; 751 int rval; 752 int minor_node_type; 753 754 if (usb_ugen_hdl == NULL) { 755 756 return (EINVAL); 757 } 758 759 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 760 761 if (ugen_is_valid_minor_node(ugenp, *devp) != USB_SUCCESS) { 762 763 return (EINVAL); 764 } 765 766 minor_node_type = UGEN_MINOR_TYPE(ugenp, *devp); 767 768 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 769 "usb_ugen_open: minor=%u", getminor(*devp)); 770 USB_DPRINTF_L3(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 771 "cfgval=%" PRIu64 " cfgidx=%" PRIu64 " if=%" PRIu64 772 " alt=%" PRIu64 " epidx=%" PRIu64 " type=0x%" PRIx64, 773 UGEN_MINOR_CFGVAL(ugenp, *devp), UGEN_MINOR_CFGIDX(ugenp, *devp), 774 UGEN_MINOR_IF(ugenp, *devp), UGEN_MINOR_ALT(ugenp, *devp), 775 UGEN_MINOR_EPIDX(ugenp, *devp), UGEN_MINOR_TYPE(ugenp, *devp)); 776 777 /* first check for legal open flags */ 778 if ((rval = ugen_check_open_flags(ugenp, *devp, flag)) != 0) { 779 USB_DPRINTF_L2(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 780 "usb_ugen_open: check failed, rval=%d", rval); 781 782 return (rval); 783 } 784 785 /* exclude other threads including other opens */ 786 if (usb_serialize_access(ugenp->ug_ser_cookie, 787 USB_WAIT_SIG, 0) <= 0) { 788 USB_DPRINTF_L2(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 789 "usb_ugen_open: interrupted"); 790 791 return (EINTR); 792 } 793 794 mutex_enter(&ugenp->ug_mutex); 795 796 /* always allow open of dev stat node */ 797 if (minor_node_type != UGEN_MINOR_DEV_STAT_NODE) { 798 799 /* if we are not online or powered down, fail open */ 800 switch (ugenp->ug_dev_state) { 801 case USB_DEV_ONLINE: 802 803 break; 804 case USB_DEV_DISCONNECTED: 805 rval = ENODEV; 806 mutex_exit(&ugenp->ug_mutex); 807 808 goto done; 809 case USB_DEV_SUSPENDED: 810 case USB_UGEN_DEV_UNAVAILABLE_RESUME: 811 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 812 default: 813 rval = EBADF; 814 mutex_exit(&ugenp->ug_mutex); 815 816 goto done; 817 } 818 } 819 mutex_exit(&ugenp->ug_mutex); 820 821 /* open node depending on type */ 822 switch (minor_node_type) { 823 case UGEN_MINOR_EP_XFER_NODE: 824 if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 825 ugen_pm_busy_component(ugenp); 826 (void) pm_raise_power(ugenp->ug_dip, 0, 827 USB_DEV_OS_FULL_PWR); 828 } 829 830 rval = ugen_epx_open(ugenp, *devp, flag); 831 if (rval == 0) { 832 mutex_enter(&ugenp->ug_mutex); 833 ugenp->ug_open_count++; 834 mutex_exit(&ugenp->ug_mutex); 835 } else { 836 if (ugenp->ug_hdl->hdl_flags & 837 USB_UGEN_ENABLE_PM) { 838 ugen_pm_idle_component(ugenp); 839 } 840 } 841 842 break; 843 case UGEN_MINOR_EP_STAT_NODE: 844 rval = ugen_eps_open(ugenp, *devp, flag); 845 if (rval == 0) { 846 mutex_enter(&ugenp->ug_mutex); 847 ugenp->ug_open_count++; 848 mutex_exit(&ugenp->ug_mutex); 849 } 850 851 break; 852 case UGEN_MINOR_DEV_STAT_NODE: 853 rval = ugen_ds_open(ugenp, *devp, flag); 854 855 break; 856 default: 857 rval = EINVAL; 858 859 break; 860 } 861 done: 862 mutex_enter(&ugenp->ug_mutex); 863 864 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 865 "usb_ugen_open: minor=0x%x rval=%d state=%d cnt=%d", 866 getminor(*devp), rval, ugenp->ug_dev_state, 867 ugenp->ug_open_count); 868 869 mutex_exit(&ugenp->ug_mutex); 870 871 usb_release_access(ugenp->ug_ser_cookie); 872 873 return (rval); 874 } 875 876 877 /* 878 * usb_ugen_close() 879 */ 880 /* ARGSUSED */ 881 int 882 usb_ugen_close(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, int flag, int otype, 883 cred_t *cr) 884 { 885 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 886 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 887 ugen_state_t *ugenp; 888 int minor_node_type; 889 890 if (usb_ugen_hdl == NULL) { 891 892 return (EINVAL); 893 } 894 895 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 896 if (ugen_is_valid_minor_node(ugenp, dev) != USB_SUCCESS) { 897 898 return (EINVAL); 899 } 900 901 minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 902 903 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 904 "usb_ugen_close: minor=0x%x", getminor(dev)); 905 906 /* exclude other threads, including other opens */ 907 if (usb_serialize_access(ugenp->ug_ser_cookie, 908 USB_WAIT_SIG, 0) <= 0) { 909 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 910 "usb_ugen_close: interrupted"); 911 912 return (EINTR); 913 } 914 915 /* close node depending on type */ 916 switch (minor_node_type) { 917 case UGEN_MINOR_EP_XFER_NODE: 918 ugen_epx_close(ugenp, dev, flag); 919 if (ugenp->ug_hdl->hdl_flags & USB_UGEN_ENABLE_PM) { 920 ugen_pm_idle_component(ugenp); 921 } 922 923 break; 924 case UGEN_MINOR_EP_STAT_NODE: 925 ugen_eps_close(ugenp, dev, flag); 926 927 break; 928 case UGEN_MINOR_DEV_STAT_NODE: 929 ugen_ds_close(ugenp, dev, flag); 930 931 break; 932 default: 933 usb_release_access(ugenp->ug_ser_cookie); 934 935 return (EINVAL); 936 } 937 938 mutex_enter(&ugenp->ug_mutex); 939 if (minor_node_type != UGEN_MINOR_DEV_STAT_NODE) { 940 ASSERT(ugenp->ug_open_count > 0); 941 if ((--ugenp->ug_open_count == 0) && 942 ((ugenp->ug_dev_state == USB_UGEN_DEV_UNAVAILABLE_RESUME) || 943 (ugenp->ug_dev_state == 944 USB_UGEN_DEV_UNAVAILABLE_RECONNECT))) { 945 ugenp->ug_dev_state = USB_DEV_ONLINE; 946 947 /* wakeup devstat reads and polls */ 948 ugen_ds_change(ugenp); 949 ugen_ds_poll_wakeup(ugenp); 950 } 951 } 952 953 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 954 "usb_ugen_close: minor=0x%x state=%d cnt=%d", 955 getminor(dev), ugenp->ug_dev_state, ugenp->ug_open_count); 956 957 if (ugenp->ug_open_count == 0) { 958 ASSERT(ugen_epxs_check_open_nodes(ugenp) == USB_FAILURE); 959 } 960 961 mutex_exit(&ugenp->ug_mutex); 962 963 usb_release_access(ugenp->ug_ser_cookie); 964 965 return (0); 966 } 967 968 969 /* 970 * usb_ugen_read/write() 971 */ 972 /*ARGSUSED*/ 973 int 974 usb_ugen_read(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, struct uio *uiop, 975 cred_t *credp) 976 { 977 ugen_state_t *ugenp; 978 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 979 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 980 981 if (usb_ugen_hdl == NULL) { 982 983 return (EINVAL); 984 } 985 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 986 987 if (ugen_is_valid_minor_node(ugenp, dev) != USB_SUCCESS) { 988 989 return (EINVAL); 990 } 991 992 return (physio(ugen_strategy, 993 (struct buf *)0, dev, B_READ, ugen_minphys, uiop)); 994 } 995 996 997 /*ARGSUSED*/ 998 int 999 usb_ugen_write(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, struct uio *uiop, 1000 cred_t *credp) 1001 { 1002 ugen_state_t *ugenp; 1003 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 1004 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 1005 1006 if (usb_ugen_hdl == NULL) { 1007 1008 return (EINVAL); 1009 } 1010 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 1011 1012 if (ugen_is_valid_minor_node(ugenp, dev) != USB_SUCCESS) { 1013 1014 return (EINVAL); 1015 } 1016 1017 return (physio(ugen_strategy, 1018 (struct buf *)0, dev, B_WRITE, ugen_minphys, uiop)); 1019 } 1020 1021 1022 /* 1023 * usb_ugen_poll 1024 */ 1025 int 1026 usb_ugen_poll(usb_ugen_hdl_t usb_ugen_hdl, dev_t dev, short events, 1027 int anyyet, short *reventsp, struct pollhead **phpp) 1028 { 1029 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 1030 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 1031 ugen_state_t *ugenp; 1032 int minor_node_type; 1033 uint_t ep_index; 1034 ugen_ep_t *epp; 1035 1036 if (usb_ugen_hdl == NULL) { 1037 1038 return (EINVAL); 1039 } 1040 1041 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 1042 if (ugen_is_valid_minor_node(ugenp, dev) != USB_SUCCESS) { 1043 1044 return (EINVAL); 1045 } 1046 1047 minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1048 ep_index = UGEN_MINOR_EPIDX(ugenp, dev); 1049 epp = &ugenp->ug_ep[ep_index]; 1050 1051 mutex_enter(&ugenp->ug_mutex); 1052 1053 USB_DPRINTF_L4(UGEN_PRINT_POLL, ugenp->ug_log_hdl, 1054 "usb_ugen_poll: " 1055 "dev=0x%lx events=0x%x anyyet=0x%x rev=0x%p type=%d " 1056 "devstat=0x%x devstate=0x%x", 1057 dev, events, anyyet, (void *)reventsp, minor_node_type, 1058 ugenp->ug_ds.dev_stat, ugenp->ug_ds.dev_state); 1059 1060 *reventsp = 0; 1061 1062 if (ugenp->ug_dev_state == USB_DEV_ONLINE) { 1063 switch (minor_node_type) { 1064 case UGEN_MINOR_EP_XFER_NODE: 1065 /* if interrupt IN ep and there is data, set POLLIN */ 1066 if ((UGEN_XFER_TYPE(epp) == USB_EP_ATTR_INTR) && 1067 (UGEN_XFER_DIR(epp) & USB_EP_DIR_IN)) { 1068 1069 /* 1070 * if we are not polling, force another 1071 * read to kick off polling 1072 */ 1073 mutex_enter(&epp->ep_mutex); 1074 if ((epp->ep_data) || 1075 ((epp->ep_state & 1076 UGEN_EP_STATE_INTR_IN_POLLING_ON) == 0)) { 1077 *reventsp |= POLLIN; 1078 } else if (!anyyet) { 1079 *phpp = &epp->ep_pollhead; 1080 epp->ep_state |= 1081 UGEN_EP_STATE_INTR_IN_POLL_PENDING; 1082 } 1083 mutex_exit(&epp->ep_mutex); 1084 } else { 1085 /* no poll on other ep nodes */ 1086 *reventsp |= POLLERR; 1087 } 1088 1089 break; 1090 case UGEN_MINOR_DEV_STAT_NODE: 1091 if (ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_CHANGED) { 1092 *reventsp |= POLLIN; 1093 } else if (!anyyet) { 1094 *phpp = &ugenp->ug_ds.dev_pollhead; 1095 ugenp->ug_ds.dev_stat |= 1096 UGEN_DEV_STATUS_POLL_PENDING; 1097 } 1098 1099 break; 1100 case UGEN_MINOR_EP_STAT_NODE: 1101 default: 1102 *reventsp |= POLLERR; 1103 1104 break; 1105 } 1106 } else { 1107 if (ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_CHANGED) { 1108 *reventsp |= POLLHUP|POLLIN; 1109 } else if (!anyyet) { 1110 *phpp = &ugenp->ug_ds.dev_pollhead; 1111 ugenp->ug_ds.dev_stat |= 1112 UGEN_DEV_STATUS_POLL_PENDING; 1113 } 1114 } 1115 1116 mutex_exit(&ugenp->ug_mutex); 1117 1118 USB_DPRINTF_L4(UGEN_PRINT_POLL, ugenp->ug_log_hdl, 1119 "usb_ugen_poll end: reventsp=0x%x", *reventsp); 1120 1121 return (0); 1122 } 1123 1124 1125 /* 1126 * ugen_strategy 1127 */ 1128 static int 1129 ugen_strategy(struct buf *bp) 1130 { 1131 dev_t dev = bp->b_edev; 1132 int rval = 0; 1133 ugen_state_t *ugenp = ugen_devt2state(dev); 1134 int minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1135 1136 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1137 "ugen_strategy: bp=0x%p minor=0x%x", bp, getminor(dev)); 1138 1139 if (ugen_is_valid_minor_node(ugenp, dev) != USB_SUCCESS) { 1140 1141 return (EINVAL); 1142 } 1143 1144 mutex_enter(&ugenp->ug_mutex); 1145 ugenp->ug_pending_cmds++; 1146 mutex_exit(&ugenp->ug_mutex); 1147 1148 bp_mapin(bp); 1149 1150 switch (minor_node_type) { 1151 case UGEN_MINOR_EP_XFER_NODE: 1152 rval = ugen_epx_req(ugenp, bp); 1153 1154 break; 1155 case UGEN_MINOR_EP_STAT_NODE: 1156 rval = ugen_eps_req(ugenp, bp); 1157 1158 break; 1159 case UGEN_MINOR_DEV_STAT_NODE: 1160 rval = ugen_ds_req(ugenp, bp); 1161 1162 break; 1163 default: 1164 rval = EINVAL; 1165 1166 break; 1167 } 1168 1169 mutex_enter(&ugenp->ug_mutex); 1170 ugenp->ug_pending_cmds--; 1171 1172 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1173 "ugen_strategy: " 1174 "bp=0x%p cnt=%lu resid=%lu err=%d minor=0x%x rval=%d #cmds=%d", 1175 (void *)bp, bp->b_bcount, bp->b_resid, geterror(bp), 1176 getminor(dev), rval, ugenp->ug_pending_cmds); 1177 1178 mutex_exit(&ugenp->ug_mutex); 1179 1180 if (rval) { 1181 if (geterror(bp) == 0) { 1182 bioerror(bp, rval); 1183 } 1184 } 1185 1186 biodone(bp); 1187 1188 return (0); 1189 } 1190 1191 1192 /* 1193 * ugen_minphys: 1194 */ 1195 static void 1196 ugen_minphys(struct buf *bp) 1197 { 1198 dev_t dev = bp->b_edev; 1199 ugen_state_t *ugenp = ugen_devt2state(dev); 1200 int minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1201 uint_t ep_index = UGEN_MINOR_EPIDX(ugenp, dev); 1202 ugen_ep_t *epp = &ugenp->ug_ep[ep_index]; 1203 1204 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1205 "ugen_phys: bp=0x%p dev=0x%lx index=%d type=0x%x", 1206 (void *)bp, dev, ep_index, minor_node_type); 1207 1208 switch (minor_node_type) { 1209 case UGEN_MINOR_EP_XFER_NODE: 1210 switch (UGEN_XFER_TYPE(epp)) { 1211 case USB_EP_ATTR_BULK: 1212 if (bp->b_bcount > ugenp->ug_max_bulk_xfer_sz) { 1213 bp->b_bcount = ugenp->ug_max_bulk_xfer_sz; 1214 } 1215 1216 break; 1217 case USB_EP_ATTR_INTR: 1218 case USB_EP_ATTR_CONTROL: 1219 default: 1220 1221 break; 1222 } 1223 break; 1224 case UGEN_MINOR_EP_STAT_NODE: 1225 case UGEN_MINOR_DEV_STAT_NODE: 1226 default: 1227 1228 break; 1229 } 1230 } 1231 1232 1233 /* 1234 * check whether flag is appropriate for node type 1235 */ 1236 static int 1237 ugen_check_open_flags(ugen_state_t *ugenp, dev_t dev, int flag) 1238 { 1239 ugen_ep_t *epp; 1240 int minor_node_type = UGEN_MINOR_TYPE(ugenp, dev); 1241 int rval = 0; 1242 1243 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1244 "ugen_check_open_flags: " 1245 "dev=0x%lx, type=0x%x flag=0x%x idx=%" PRIu64, 1246 dev, minor_node_type, flag, UGEN_MINOR_EPIDX(ugenp, dev)); 1247 1248 switch (minor_node_type) { 1249 case UGEN_MINOR_EP_XFER_NODE: 1250 epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 1251 switch (UGEN_XFER_TYPE(epp)) { 1252 case USB_EP_ATTR_CONTROL: 1253 /* read and write must be set, ndelay not allowed */ 1254 if (((flag & (FREAD | FWRITE)) != (FREAD | FWRITE)) || 1255 (flag & (FNDELAY | FNONBLOCK))) { 1256 rval = EACCES; 1257 } 1258 1259 break; 1260 case USB_EP_ATTR_BULK: 1261 /* ndelay not allowed */ 1262 if (flag & (FNDELAY | FNONBLOCK)) { 1263 rval = EACCES; 1264 1265 break; 1266 } 1267 /*FALLTHRU*/ 1268 case USB_EP_ATTR_ISOCH: 1269 case USB_EP_ATTR_INTR: 1270 /* check flag versus direction */ 1271 if ((flag & FWRITE) && 1272 (UGEN_XFER_DIR(epp) & USB_EP_DIR_IN)) { 1273 rval = EACCES; 1274 } 1275 if ((flag & FREAD) && 1276 ((UGEN_XFER_DIR(epp) & USB_EP_DIR_IN) == 0)) { 1277 rval = EACCES; 1278 } 1279 1280 break; 1281 default: 1282 rval = EINVAL; 1283 1284 break; 1285 } 1286 break; 1287 case UGEN_MINOR_DEV_STAT_NODE: 1288 /* only reads are supported */ 1289 if (flag & FWRITE) { 1290 rval = EACCES; 1291 } 1292 1293 break; 1294 case UGEN_MINOR_EP_STAT_NODE: 1295 1296 break; 1297 default: 1298 rval = EINVAL; 1299 1300 break; 1301 } 1302 1303 return (rval); 1304 } 1305 1306 1307 /* 1308 * endpoint management 1309 * 1310 * create/initialize all endpoint xfer/stat structures 1311 */ 1312 static int 1313 ugen_epxs_init(ugen_state_t *ugenp) 1314 { 1315 usb_cfg_data_t *dev_cfg = ugenp->ug_dev_data->dev_cfg; 1316 uchar_t cfgidx, cfgval, iface, alt, ep; 1317 usb_if_data_t *if_data; 1318 usb_alt_if_data_t *alt_if_data; 1319 usb_ep_data_t *ep_data; 1320 1321 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1322 "ugen_epxs_init:"); 1323 1324 /* initialize each ep's mutex first */ 1325 for (ep = 0; ep < UGEN_N_ENDPOINTS; ep++) { 1326 mutex_init(&ugenp->ug_ep[ep].ep_mutex, NULL, MUTEX_DRIVER, 1327 ugenp->ug_dev_data->dev_iblock_cookie); 1328 } 1329 1330 /* init default ep as it does not have a descriptor */ 1331 if (ugen_epxs_data_init(ugenp, NULL, 0, 0, 1332 ugenp->ug_dev_data->dev_curr_if, 0) != USB_SUCCESS) { 1333 USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 1334 "creating default endpoint failed"); 1335 1336 return (USB_FAILURE); 1337 } 1338 1339 /* 1340 * walk all endpoints of all alternates of all interfaces of 1341 * all cfs 1342 */ 1343 for (cfgidx = 0; cfgidx < ugenp->ug_dev_data->dev_n_cfg; cfgidx++) { 1344 dev_cfg = &ugenp->ug_dev_data->dev_cfg[cfgidx]; 1345 cfgval = dev_cfg->cfg_descr.bConfigurationValue; 1346 for (iface = 0; iface < dev_cfg->cfg_n_if; iface++) { 1347 if_data = &dev_cfg->cfg_if[iface]; 1348 for (alt = 0; alt < if_data->if_n_alt; alt++) { 1349 alt_if_data = &if_data->if_alt[alt]; 1350 for (ep = 0; ep < alt_if_data->altif_n_ep; 1351 ep++) { 1352 ep_data = &alt_if_data->altif_ep[ep]; 1353 if (ugen_epxs_data_init(ugenp, ep_data, 1354 cfgval, cfgidx, iface, alt) != 1355 USB_SUCCESS) { 1356 1357 return (USB_FAILURE); 1358 } 1359 } 1360 } 1361 } 1362 } 1363 1364 return (USB_SUCCESS); 1365 } 1366 1367 1368 /* 1369 * initialize one endpoint structure 1370 */ 1371 static int 1372 ugen_epxs_data_init(ugen_state_t *ugenp, usb_ep_data_t *ep_data, 1373 uchar_t cfgval, uchar_t cfgidx, uchar_t iface, uchar_t alt) 1374 { 1375 int ep_index; 1376 ugen_ep_t *epp; 1377 usb_ep_descr_t *ep_descr; 1378 1379 /* is this the default endpoint */ 1380 ep_index = (ep_data == NULL) ? 0 : 1381 usb_get_ep_index(ep_data->ep_descr.bEndpointAddress); 1382 epp = &ugenp->ug_ep[ep_index]; 1383 1384 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1385 "ugen_epxs_data_init: " 1386 "cfgval=%d cfgidx=%d iface=%d alt=%d ep_index=%d", 1387 cfgval, cfgidx, iface, alt, ep_index); 1388 1389 ep_descr = (ep_data == NULL) ? &ugen_default_ep_descr : 1390 &ep_data->ep_descr; 1391 1392 mutex_init(&epp->ep_mutex, NULL, MUTEX_DRIVER, 1393 ugenp->ug_dev_data->dev_iblock_cookie); 1394 1395 mutex_enter(&epp->ep_mutex); 1396 1397 /* initialize if not yet init'ed */ 1398 if (epp->ep_state == UGEN_EP_STATE_NONE) { 1399 epp->ep_descr = *ep_descr; 1400 epp->ep_cfgidx = cfgidx; 1401 epp->ep_if = iface; 1402 epp->ep_alt = alt; 1403 epp->ep_state = UGEN_EP_STATE_ACTIVE; 1404 epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 1405 epp->ep_pipe_policy.pp_max_async_reqs = 1; 1406 1407 cv_init(&epp->ep_wait_cv, NULL, CV_DRIVER, NULL); 1408 epp->ep_ser_cookie = usb_init_serialization( 1409 ugenp->ug_dip, 0); 1410 } 1411 1412 mutex_exit(&epp->ep_mutex); 1413 1414 /* create minor nodes for all alts */ 1415 1416 return (ugen_epxs_minor_nodes_create(ugenp, ep_descr, 1417 cfgval, cfgidx, iface, alt)); 1418 } 1419 1420 1421 /* 1422 * undo all endpoint initializations 1423 */ 1424 static void 1425 ugen_epxs_destroy(ugen_state_t *ugenp) 1426 { 1427 int i; 1428 1429 for (i = 0; i < UGEN_N_ENDPOINTS; i++) { 1430 ugen_epxs_data_destroy(ugenp, &ugenp->ug_ep[i]); 1431 } 1432 } 1433 1434 1435 static void 1436 ugen_epxs_data_destroy(ugen_state_t *ugenp, ugen_ep_t *epp) 1437 { 1438 if (epp) { 1439 ASSERT(epp->ep_ph == NULL); 1440 mutex_enter(&epp->ep_mutex); 1441 if (epp->ep_state != UGEN_EP_STATE_NONE) { 1442 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1443 "ugen_epxs_destroy: addr=0x%x", 1444 UGEN_XFER_ADDR(epp)); 1445 cv_destroy(&epp->ep_wait_cv); 1446 } 1447 mutex_exit(&epp->ep_mutex); 1448 1449 mutex_destroy(&epp->ep_mutex); 1450 usb_fini_serialization(epp->ep_ser_cookie); 1451 } 1452 } 1453 1454 1455 /* 1456 * create endpoint status and xfer minor nodes 1457 * 1458 * The actual minor node needs more than 18 bits. We create a table 1459 * and store the full minor node in this table and use the 1460 * index in the table as minor node. This allows 256 minor nodes 1461 * and 1024 instances 1462 */ 1463 static int 1464 ugen_epxs_minor_nodes_create(ugen_state_t *ugenp, usb_ep_descr_t *ep_descr, 1465 uchar_t cfgval, uchar_t cfgidx, uchar_t iface, uchar_t alt) 1466 { 1467 char node_name[32], *type; 1468 int vid = ugenp->ug_dev_data->dev_descr->idVendor; 1469 int pid = ugenp->ug_dev_data->dev_descr->idProduct; 1470 minor_t minor; 1471 int minor_index; 1472 ugen_minor_t minor_code, minor_code_base; 1473 int owns_device = (usb_owns_device(ugenp->ug_dip) ? 1474 UGEN_OWNS_DEVICE : 0); 1475 int ep_index = 1476 usb_get_ep_index(ep_descr->bEndpointAddress); 1477 int ep_addr = 1478 ep_descr->bEndpointAddress & USB_EP_NUM_MASK; 1479 int ep_type = 1480 ep_descr->bmAttributes & USB_EP_ATTR_MASK; 1481 int ep_dir = 1482 ep_descr->bEndpointAddress & USB_EP_DIR_IN; 1483 1484 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1485 "ugen_epxs_minor_nodes_create: " 1486 "cfgval=%d cfgidx=%d if=%d alt=%d ep=0x%x", 1487 cfgval, cfgidx, iface, alt, ep_addr); 1488 1489 if (ugenp->ug_instance >= UGEN_MINOR_INSTANCE_LIMIT(ugenp)) { 1490 USB_DPRINTF_L0(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1491 "instance number too high (%d)", ugenp->ug_instance); 1492 1493 return (USB_FAILURE); 1494 } 1495 1496 /* create stat and xfer minor node */ 1497 minor_code_base = 1498 ((ugen_minor_t)cfgval) << UGEN_MINOR_CFGVAL_SHIFT | 1499 ((ugen_minor_t)cfgidx) << UGEN_MINOR_CFGIDX_SHIFT | 1500 iface << UGEN_MINOR_IF_SHIFT | 1501 alt << UGEN_MINOR_ALT_SHIFT | 1502 ep_index << UGEN_MINOR_EPIDX_SHIFT | owns_device; 1503 minor_code = minor_code_base | UGEN_MINOR_EP_XFER_NODE; 1504 1505 minor_index = ugen_minor_index_create(ugenp, minor_code); 1506 if (minor_index < 0) { 1507 USB_DPRINTF_L1(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1508 "too many minor nodes, " 1509 "cannot create %d.%d.%d.%x", 1510 cfgval, iface, alt, ep_addr); 1511 /* carry on regardless */ 1512 1513 return (USB_SUCCESS); 1514 } 1515 minor = (minor_index << UGEN_MINOR_IDX_SHIFT(ugenp)) | 1516 ugenp->ug_instance << UGEN_MINOR_INSTANCE_SHIFT(ugenp); 1517 1518 if (ep_type == USB_EP_ATTR_CONTROL) { 1519 type = "cntrl"; 1520 } else { 1521 type = (ep_dir & USB_EP_DIR_IN) ? "in" : "out"; 1522 } 1523 1524 /* 1525 * xfer ep node name: 1526 * vid.pid.[in|out|cntrl].[<cfg>.][if<iface>.][<alt>.]<ep addr> 1527 */ 1528 if ((ep_addr == 0) && owns_device) { 1529 (void) sprintf(node_name, "%x.%x.%s%d", 1530 vid, pid, type, ep_addr); 1531 } else if (cfgidx == 0 && alt == 0) { 1532 (void) sprintf(node_name, "%x.%x.if%d%s%d", 1533 vid, pid, iface, type, ep_addr); 1534 } else if (cfgidx == 0 && alt != 0) { 1535 (void) sprintf(node_name, "%x.%x.if%d.%d%s%d", 1536 vid, pid, iface, alt, type, ep_addr); 1537 } else if (cfgidx != 0 && alt == 0) { 1538 (void) sprintf(node_name, "%x.%x.cfg%dif%d%s%d", 1539 vid, pid, cfgval, iface, type, ep_addr); 1540 } else if (cfgidx != 0 && alt != 0) { 1541 (void) sprintf(node_name, "%x.%x.cfg%dif%d.%d%s%d", 1542 vid, pid, cfgval, iface, alt, 1543 type, ep_addr); 1544 } 1545 1546 USB_DPRINTF_L3(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1547 "minor=0x%x index=%d code=0x%" PRIx64 " name=%s", 1548 minor, minor_index, minor_code, node_name); 1549 1550 ASSERT(minor < L_MAXMIN); 1551 1552 if ((ddi_create_minor_node(ugenp->ug_dip, node_name, 1553 S_IFCHR, minor, DDI_NT_UGEN, 0)) != DDI_SUCCESS) { 1554 1555 return (USB_FAILURE); 1556 } 1557 1558 ugen_store_devt(ugenp, minor); 1559 1560 minor_code = minor_code_base | UGEN_MINOR_EP_STAT_NODE; 1561 minor_index = ugen_minor_index_create(ugenp, minor_code); 1562 if (minor_index < 0) { 1563 USB_DPRINTF_L1(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1564 "too many minor nodes, " 1565 "cannot create %d.%d.%d.%x stat", 1566 cfgval, iface, alt, 1567 ep_descr->bEndpointAddress); 1568 /* carry on regardless */ 1569 1570 return (USB_SUCCESS); 1571 } 1572 minor = (minor_index << UGEN_MINOR_IDX_SHIFT(ugenp)) | 1573 ugenp->ug_instance << UGEN_MINOR_INSTANCE_SHIFT(ugenp); 1574 1575 (void) strcat(node_name, "stat"); 1576 1577 USB_DPRINTF_L3(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 1578 "minor=0x%x index=%d code=0x%" PRIx64 " name=%s", 1579 minor, minor_index, minor_code, node_name); 1580 1581 ASSERT(minor < L_MAXMIN); 1582 1583 if ((ddi_create_minor_node(ugenp->ug_dip, node_name, 1584 S_IFCHR, minor, DDI_NT_UGEN, 0)) != DDI_SUCCESS) { 1585 1586 return (USB_FAILURE); 1587 } 1588 1589 ugen_store_devt(ugenp, minor); 1590 1591 return (USB_SUCCESS); 1592 } 1593 1594 1595 /* 1596 * close all non-default pipes and drain default pipe 1597 */ 1598 static void 1599 ugen_epx_shutdown(ugen_state_t *ugenp) 1600 { 1601 int i; 1602 1603 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1604 "ugen_epx_shutdown:"); 1605 1606 for (i = 0; i < UGEN_N_ENDPOINTS; i++) { 1607 ugen_ep_t *epp = &ugenp->ug_ep[i]; 1608 mutex_enter(&epp->ep_mutex); 1609 if (epp->ep_state != UGEN_EP_STATE_NONE) { 1610 mutex_exit(&epp->ep_mutex); 1611 (void) usb_serialize_access(epp->ep_ser_cookie, 1612 USB_WAIT, 0); 1613 (void) ugen_epx_close_pipe(ugenp, epp); 1614 usb_release_access(epp->ep_ser_cookie); 1615 } else { 1616 mutex_exit(&epp->ep_mutex); 1617 } 1618 } 1619 } 1620 1621 1622 /* 1623 * find cfg index corresponding to cfg value 1624 */ 1625 static int 1626 ugen_cfgval2idx(ugen_state_t *ugenp, uint_t cfgval) 1627 { 1628 usb_cfg_data_t *dev_cfg = ugenp->ug_dev_data->dev_cfg; 1629 int cfgidx; 1630 1631 for (cfgidx = 0; cfgidx < ugenp->ug_dev_data->dev_n_cfg; cfgidx++) { 1632 dev_cfg = &ugenp->ug_dev_data->dev_cfg[cfgidx]; 1633 if (cfgval == dev_cfg->cfg_descr.bConfigurationValue) { 1634 1635 return (cfgidx); 1636 } 1637 } 1638 1639 ASSERT(cfgidx < ugenp->ug_dev_data->dev_n_cfg); 1640 1641 return (0); 1642 } 1643 1644 1645 /* 1646 * check if any node is open 1647 */ 1648 static int 1649 ugen_epxs_check_open_nodes(ugen_state_t *ugenp) 1650 { 1651 int i; 1652 1653 for (i = 1; i < UGEN_N_ENDPOINTS; i++) { 1654 ugen_ep_t *epp = &ugenp->ug_ep[i]; 1655 1656 mutex_enter(&epp->ep_mutex); 1657 1658 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1659 "ugen_epxs_check_open_nodes: epp=%d, ep_state=0x%x", 1660 i, epp->ep_state); 1661 1662 if (epp->ep_state & UGEN_EP_STATE_XS_OPEN) { 1663 mutex_exit(&epp->ep_mutex); 1664 1665 return (USB_SUCCESS); 1666 } 1667 mutex_exit(&epp->ep_mutex); 1668 } 1669 1670 return (USB_FAILURE); 1671 } 1672 1673 1674 /* 1675 * check if we can switch alternate 1676 */ 1677 static int 1678 ugen_epxs_check_alt_switch(ugen_state_t *ugenp, uchar_t iface, uchar_t cfgidx) 1679 { 1680 int i; 1681 1682 for (i = 1; i < UGEN_N_ENDPOINTS; i++) { 1683 ugen_ep_t *epp = &ugenp->ug_ep[i]; 1684 1685 mutex_enter(&epp->ep_mutex); 1686 1687 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1688 "ugen_epxs_check_alt_switch: epp=%d, ep_state=0x%x", 1689 i, epp->ep_state); 1690 1691 /* 1692 * if the endpoint is open and part of this cfg and interface 1693 * then we cannot switch alternates 1694 */ 1695 if ((epp->ep_state & UGEN_EP_STATE_XS_OPEN) && 1696 (epp->ep_cfgidx == cfgidx) && 1697 (epp->ep_if == iface)) { 1698 mutex_exit(&epp->ep_mutex); 1699 1700 return (USB_FAILURE); 1701 } 1702 mutex_exit(&epp->ep_mutex); 1703 } 1704 1705 return (USB_SUCCESS); 1706 } 1707 1708 1709 /* 1710 * implicit switch to new cfg and alt 1711 * If a crummy device fails usb_get_cfg or usb_get_alt_if, we carry on 1712 * regardless so at least the device can be opened. 1713 */ 1714 static int 1715 ugen_epxs_switch_cfg_alt(ugen_state_t *ugenp, ugen_ep_t *epp, dev_t dev) 1716 { 1717 int rval = USB_SUCCESS; 1718 uint_t alt; 1719 uint_t new_alt = UGEN_MINOR_ALT(ugenp, dev); 1720 uint_t new_if = UGEN_MINOR_IF(ugenp, dev); 1721 uint_t cur_if = epp->ep_if; 1722 uint_t new_cfgidx = UGEN_MINOR_CFGIDX(ugenp, dev); 1723 uint_t cur_cfgidx; 1724 uint_t cfgval; 1725 int switched = 0; 1726 1727 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1728 "ugen_epxs_switch_cfg_alt: old cfgidx=%d, if=%d alt=%d", 1729 epp->ep_cfgidx, epp->ep_if, epp->ep_alt); 1730 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1731 "new cfgidx=%d, if=%d alt=%d ep_state=0x%x", 1732 new_cfgidx, new_if, new_alt, epp->ep_state); 1733 1734 /* no need to switch if there is only 1 cfg, 1 iface and no alts */ 1735 if ((new_if == 0) && (new_alt == 0) && 1736 (ugenp->ug_dev_data->dev_n_cfg == 1) && 1737 (ugenp->ug_dev_data->dev_cfg[0].cfg_n_if == 1) && 1738 (ugenp->ug_dev_data-> 1739 dev_cfg[0].cfg_if[new_if].if_n_alt == 1)) { 1740 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1741 "no need for switching: n_cfg=%d n_alt=%d", 1742 ugenp->ug_dev_data->dev_n_cfg, 1743 ugenp->ug_dev_data-> 1744 dev_cfg[0].cfg_if[new_if].if_n_alt); 1745 1746 ASSERT(epp->ep_alt == new_alt); 1747 ASSERT(epp->ep_cfgidx == new_cfgidx); 1748 ASSERT(epp->ep_if == new_if); 1749 1750 return (rval); 1751 } 1752 1753 /* no switch for default endpoint */ 1754 if (epp->ep_descr.bEndpointAddress == 0) { 1755 1756 return (rval); 1757 } 1758 1759 mutex_exit(&epp->ep_mutex); 1760 if ((ugenp->ug_dev_data->dev_n_cfg > 1) && 1761 usb_get_cfg(ugenp->ug_dip, &cfgval, 1762 USB_FLAGS_SLEEP) == USB_SUCCESS) { 1763 1764 mutex_enter(&epp->ep_mutex); 1765 1766 cur_cfgidx = ugen_cfgval2idx(ugenp, cfgval); 1767 1768 if (new_cfgidx != cur_cfgidx) { 1769 mutex_exit(&epp->ep_mutex); 1770 1771 /* 1772 * we can't change config if any node 1773 * is open 1774 */ 1775 if (ugen_epxs_check_open_nodes(ugenp) == 1776 USB_SUCCESS) { 1777 mutex_enter(&epp->ep_mutex); 1778 1779 return (USB_BUSY); 1780 } 1781 1782 /* 1783 * we are going to do this synchronously to 1784 * keep it simple. 1785 * This should never hang forever. 1786 */ 1787 if ((rval = usb_set_cfg(ugenp->ug_dip, 1788 new_cfgidx, USB_FLAGS_SLEEP, NULL, 1789 NULL)) != USB_SUCCESS) { 1790 USB_DPRINTF_L2(UGEN_PRINT_XFER, 1791 ugenp->ug_log_hdl, 1792 "implicit set cfg (%" PRId64 1793 ") failed (%d)", 1794 UGEN_MINOR_CFGIDX(ugenp, dev), rval); 1795 mutex_enter(&epp->ep_mutex); 1796 1797 return (rval); 1798 } 1799 mutex_enter(&epp->ep_mutex); 1800 epp->ep_if = new_if; 1801 switched++; 1802 } 1803 epp->ep_cfgidx = new_cfgidx; 1804 1805 mutex_exit(&epp->ep_mutex); 1806 } 1807 1808 /* 1809 * implicitly switch to new alternate if 1810 * - we have not switched configuration (if we 1811 * we switched config, the alternate must be 0) 1812 * - n_alts is > 1 1813 * - if the device supports get_alternate iface 1814 */ 1815 if ((switched && (new_alt > 0)) || 1816 ((ugenp->ug_dev_data->dev_cfg[new_cfgidx]. 1817 cfg_if[new_if].if_n_alt > 1) && 1818 (usb_get_alt_if(ugenp->ug_dip, new_if, &alt, 1819 USB_FLAGS_SLEEP) == USB_SUCCESS))) { 1820 if (switched || (alt != new_alt)) { 1821 if (ugen_epxs_check_alt_switch(ugenp, cur_if, 1822 new_cfgidx) != USB_SUCCESS) { 1823 mutex_enter(&epp->ep_mutex); 1824 1825 return (USB_BUSY); 1826 } 1827 if ((rval = usb_set_alt_if(ugenp->ug_dip, new_if, 1828 new_alt, USB_FLAGS_SLEEP, NULL, NULL)) != 1829 USB_SUCCESS) { 1830 USB_DPRINTF_L2(UGEN_PRINT_XFER, 1831 ugenp->ug_log_hdl, 1832 "implicit set new alternate " 1833 "(%d) failed (%d)", new_alt, rval); 1834 mutex_enter(&epp->ep_mutex); 1835 1836 return (rval); 1837 } 1838 } 1839 } 1840 1841 mutex_enter(&epp->ep_mutex); 1842 epp->ep_alt = new_alt; 1843 ugen_update_ep_descr(ugenp, epp); 1844 1845 return (rval); 1846 } 1847 1848 1849 /* 1850 * update endpoint descriptor in ugen_ep structure after 1851 * switching configuration or alternate 1852 */ 1853 static void 1854 ugen_update_ep_descr(ugen_state_t *ugenp, ugen_ep_t *epp) 1855 { 1856 usb_cfg_data_t *dev_cfg = ugenp->ug_dev_data->dev_cfg; 1857 usb_if_data_t *if_data; 1858 usb_alt_if_data_t *alt_if_data; 1859 usb_ep_data_t *ep_data; 1860 int ep; 1861 1862 dev_cfg = &ugenp->ug_dev_data->dev_cfg[epp->ep_cfgidx]; 1863 if_data = &dev_cfg->cfg_if[epp->ep_if]; 1864 alt_if_data = &if_data->if_alt[epp->ep_alt]; 1865 for (ep = 0; ep < alt_if_data->altif_n_ep; ep++) { 1866 ep_data = &alt_if_data->altif_ep[ep]; 1867 if (usb_get_ep_index(ep_data->ep_descr. 1868 bEndpointAddress) == 1869 usb_get_ep_index(epp->ep_descr. 1870 bEndpointAddress)) { 1871 epp->ep_descr = ep_data->ep_descr; 1872 1873 break; 1874 } 1875 } 1876 } 1877 1878 1879 /* 1880 * Xfer endpoint management 1881 * 1882 * open an endpoint for xfers 1883 * 1884 * Return values: errno 1885 */ 1886 static int 1887 ugen_epx_open(ugen_state_t *ugenp, dev_t dev, int flag) 1888 { 1889 ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 1890 int rval; 1891 1892 mutex_enter(&epp->ep_mutex); 1893 1894 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1895 "ugen_epx_open: minor=0x%x flag=0x%x ep_state=0x%x", 1896 getminor(dev), flag, epp->ep_state); 1897 1898 ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 1899 1900 /* implicit switch to new cfg & alt */ 1901 if ((epp->ep_state & UGEN_EP_STATE_XFER_OPEN) != 0) { 1902 mutex_exit(&epp->ep_mutex); 1903 1904 return (EBUSY); 1905 } 1906 if ((rval = ugen_epxs_switch_cfg_alt(ugenp, epp, dev)) == 1907 USB_SUCCESS) { 1908 rval = ugen_epx_open_pipe(ugenp, epp, flag); 1909 } 1910 1911 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1912 "ugen_epx_open: state=0x%x", epp->ep_state); 1913 1914 ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 1915 epp->ep_done = epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 1916 1917 mutex_exit(&epp->ep_mutex); 1918 1919 return (usb_rval2errno(rval)); 1920 } 1921 1922 1923 /* 1924 * close an endpoint for xfers 1925 */ 1926 static void 1927 ugen_epx_close(ugen_state_t *ugenp, dev_t dev, int flag) 1928 { 1929 ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 1930 1931 mutex_enter(&epp->ep_mutex); 1932 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1933 "ugen_epx_close: dev=0x%lx flag=0x%x state=0x%x", dev, flag, 1934 epp->ep_state); 1935 mutex_exit(&epp->ep_mutex); 1936 1937 ugen_epx_close_pipe(ugenp, epp); 1938 1939 mutex_enter(&epp->ep_mutex); 1940 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1941 "ugen_epx_close: state=0x%x", epp->ep_state); 1942 ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 1943 ASSERT(epp->ep_bp == NULL); 1944 ASSERT(epp->ep_done == 0); 1945 ASSERT(epp->ep_data == NULL); 1946 mutex_exit(&epp->ep_mutex); 1947 } 1948 1949 1950 /* 1951 * open pipe for this endpoint 1952 * If the pipe is an interrupt IN pipe, start polling immediately 1953 */ 1954 static int 1955 ugen_epx_open_pipe(ugen_state_t *ugenp, ugen_ep_t *epp, int flag) 1956 { 1957 int rval = USB_SUCCESS; 1958 1959 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 1960 "ugen_epx_open_pipe: epp=0x%p flag=%d state=0x%x", 1961 epp, flag, epp->ep_state); 1962 1963 epp->ep_state |= UGEN_EP_STATE_XFER_OPEN; 1964 epp->ep_xfer_oflag = flag; 1965 1966 /* if default pipe, just copy the handle */ 1967 if ((epp->ep_descr.bEndpointAddress & USB_EP_NUM_MASK) == 0) { 1968 epp->ep_ph = ugenp->ug_dev_data->dev_default_ph; 1969 } else { 1970 mutex_exit(&epp->ep_mutex); 1971 1972 /* open pipe */ 1973 rval = usb_pipe_open(ugenp->ug_dip, 1974 &epp->ep_descr, &epp->ep_pipe_policy, 1975 USB_FLAGS_SLEEP, &epp->ep_ph); 1976 1977 mutex_enter(&epp->ep_mutex); 1978 1979 if (rval == USB_SUCCESS) { 1980 (void) usb_pipe_set_private(epp->ep_ph, 1981 (usb_opaque_t)epp); 1982 1983 /* 1984 * if interrupt IN pipe, and one xfer mode 1985 * has not been set, start polling immediately 1986 */ 1987 if ((UGEN_XFER_TYPE(epp) == USB_EP_ATTR_INTR) && 1988 (!(epp->ep_one_xfer)) && 1989 (UGEN_XFER_DIR(epp) == USB_EP_DIR_IN)) { 1990 if ((rval = ugen_epx_intr_IN_start_polling( 1991 ugenp, epp)) != USB_SUCCESS) { 1992 1993 mutex_exit(&epp->ep_mutex); 1994 usb_pipe_close(ugenp->ug_dip, 1995 epp->ep_ph, USB_FLAGS_SLEEP, 1996 NULL, NULL); 1997 mutex_enter(&epp->ep_mutex); 1998 1999 epp->ep_ph = NULL; 2000 } else { 2001 epp->ep_state |= 2002 UGEN_EP_STATE_INTR_IN_POLLING_ON; 2003 2004 /* allow for about 1 sec of data */ 2005 epp->ep_buf_limit = 2006 (1000/epp->ep_descr.bInterval) * 2007 epp->ep_descr.wMaxPacketSize; 2008 } 2009 } 2010 } 2011 } 2012 2013 if (rval != USB_SUCCESS) { 2014 epp->ep_state &= ~(UGEN_EP_STATE_XFER_OPEN | 2015 UGEN_EP_STATE_INTR_IN_POLLING_ON); 2016 } 2017 2018 return (rval); 2019 } 2020 2021 2022 /* 2023 * close an endpoint pipe 2024 */ 2025 static void 2026 ugen_epx_close_pipe(ugen_state_t *ugenp, ugen_ep_t *epp) 2027 { 2028 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2029 "ugen_epx_close_pipe: epp=0x%p", epp); 2030 2031 mutex_enter(&epp->ep_mutex); 2032 if (epp->ep_state & UGEN_EP_STATE_XFER_OPEN) { 2033 epp->ep_state &= ~(UGEN_EP_STATE_XFER_OPEN | 2034 UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED | 2035 UGEN_EP_STATE_INTR_IN_POLLING_ON); 2036 2037 if (epp->ep_ph == ugenp->ug_dev_data->dev_default_ph) { 2038 mutex_exit(&epp->ep_mutex); 2039 2040 (void) usb_pipe_drain_reqs(ugenp->ug_dip, 2041 epp->ep_ph, 0, USB_FLAGS_SLEEP, 2042 NULL, NULL); 2043 mutex_enter(&epp->ep_mutex); 2044 } else { 2045 mutex_exit(&epp->ep_mutex); 2046 usb_pipe_close(ugenp->ug_dip, 2047 epp->ep_ph, USB_FLAGS_SLEEP, NULL, NULL); 2048 2049 mutex_enter(&epp->ep_mutex); 2050 epp->ep_ph = NULL; 2051 } 2052 2053 freemsg(epp->ep_data); 2054 epp->ep_ph = NULL; 2055 epp->ep_data = NULL; 2056 } 2057 ASSERT(epp->ep_ph == NULL); 2058 ASSERT(epp->ep_data == NULL); 2059 mutex_exit(&epp->ep_mutex); 2060 } 2061 2062 2063 /* 2064 * start endpoint xfer 2065 * 2066 * We first serialize at endpoint level for only one request at the time 2067 * 2068 * Return values: errno 2069 */ 2070 static int 2071 ugen_epx_req(ugen_state_t *ugenp, struct buf *bp) 2072 { 2073 dev_t dev = bp->b_edev; 2074 ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 2075 boolean_t wait = B_FALSE; 2076 int rval = 0; 2077 2078 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2079 "ugen_epx_req: bp=0x%p dev=0x%lx", (void *)bp, dev); 2080 2081 /* single thread per endpoint, one request at the time */ 2082 if (usb_serialize_access(epp->ep_ser_cookie, USB_WAIT_SIG, 0) <= 2083 0) { 2084 2085 return (EINTR); 2086 } 2087 2088 mutex_enter(&ugenp->ug_mutex); 2089 switch (ugenp->ug_dev_state) { 2090 case USB_DEV_ONLINE: 2091 2092 break; 2093 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 2094 case USB_DEV_DISCONNECTED: 2095 mutex_enter(&epp->ep_mutex); 2096 epp->ep_lcmd_status = USB_LC_STAT_DISCONNECTED; 2097 mutex_exit(&epp->ep_mutex); 2098 rval = ENODEV; 2099 2100 break; 2101 case USB_UGEN_DEV_UNAVAILABLE_RESUME: 2102 case USB_DEV_SUSPENDED: 2103 mutex_enter(&epp->ep_mutex); 2104 epp->ep_lcmd_status = USB_LC_STAT_SUSPENDED; 2105 mutex_exit(&epp->ep_mutex); 2106 rval = EBADF; 2107 2108 break; 2109 default: 2110 mutex_enter(&epp->ep_mutex); 2111 epp->ep_lcmd_status = USB_LC_STAT_HW_ERR; 2112 mutex_exit(&epp->ep_mutex); 2113 rval = EIO; 2114 2115 break; 2116 } 2117 2118 #ifndef __lock_lint 2119 USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2120 "ugen_epx_req: lcmd_status=0x%x", epp->ep_lcmd_status); 2121 #endif 2122 2123 mutex_exit(&ugenp->ug_mutex); 2124 2125 if (rval) { 2126 usb_release_access(epp->ep_ser_cookie); 2127 2128 return (rval); 2129 } 2130 2131 mutex_enter(&epp->ep_mutex); 2132 ASSERT(epp->ep_state & UGEN_EP_STATE_XS_OPEN); 2133 epp->ep_done = 0; 2134 epp->ep_bp = bp; 2135 2136 switch (epp->ep_descr.bmAttributes & USB_EP_ATTR_MASK) { 2137 case USB_EP_ATTR_CONTROL: 2138 rval = ugen_epx_ctrl_req(ugenp, epp, bp, &wait); 2139 2140 break; 2141 case USB_EP_ATTR_BULK: 2142 rval = ugen_epx_bulk_req(ugenp, epp, bp, &wait); 2143 2144 break; 2145 case USB_EP_ATTR_INTR: 2146 if (bp->b_flags & B_READ) { 2147 rval = ugen_epx_intr_IN_req(ugenp, epp, bp, &wait); 2148 } else { 2149 rval = ugen_epx_intr_OUT_req(ugenp, epp, bp, &wait); 2150 } 2151 2152 break; 2153 case USB_EP_ATTR_ISOCH: 2154 default: 2155 epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2156 rval = USB_INVALID_REQUEST; 2157 } 2158 2159 /* if the xfer could not immediately be completed, block here */ 2160 if ((rval == USB_SUCCESS) && wait) { 2161 while (!epp->ep_done) { 2162 if ((cv_wait_sig(&epp->ep_wait_cv, 2163 &epp->ep_mutex) <= 0) && !epp->ep_done) { 2164 USB_DPRINTF_L2(UGEN_PRINT_XFER, 2165 ugenp->ug_log_hdl, 2166 "ugen_epx_req: interrupted ep=0x%" PRIx64, 2167 UGEN_MINOR_EPIDX(ugenp, dev)); 2168 2169 /* 2170 * blow away the request except for dflt pipe 2171 * (this is prevented in USBA) 2172 */ 2173 mutex_exit(&epp->ep_mutex); 2174 usb_pipe_reset(ugenp->ug_dip, epp->ep_ph, 2175 USB_FLAGS_SLEEP, NULL, NULL); 2176 (void) usb_pipe_drain_reqs(ugenp->ug_dip, 2177 epp->ep_ph, 0, 2178 USB_FLAGS_SLEEP, NULL, NULL); 2179 2180 mutex_enter(&epp->ep_mutex); 2181 2182 if (geterror(bp) == 0) { 2183 bioerror(bp, EINTR); 2184 } 2185 epp->ep_lcmd_status = 2186 USB_LC_STAT_INTERRUPTED; 2187 2188 break; 2189 } 2190 USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2191 "ugen_epx_req: wakeup"); 2192 } 2193 } 2194 2195 /* always set lcmd_status if there was a failure */ 2196 if ((rval != USB_SUCCESS) && 2197 (epp->ep_lcmd_status == USB_LC_STAT_NOERROR)) { 2198 epp->ep_lcmd_status = USB_LC_STAT_UNSPECIFIED_ERR; 2199 } 2200 2201 epp->ep_done = 0; 2202 epp->ep_bp = NULL; 2203 mutex_exit(&epp->ep_mutex); 2204 2205 usb_release_access(epp->ep_ser_cookie); 2206 USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2207 "ugen_epx_req: done"); 2208 2209 return (usb_rval2errno(rval)); 2210 } 2211 2212 2213 /* 2214 * handle control xfers 2215 */ 2216 static int 2217 ugen_epx_ctrl_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2218 struct buf *bp, boolean_t *wait) 2219 { 2220 usb_ctrl_req_t *reqp = NULL; 2221 uchar_t *setup = ((uchar_t *)(bp->b_un.b_addr)); 2222 int rval; 2223 ushort_t wLength; 2224 2225 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2226 "ugen_epx_ctrl_req: epp=0x%p state=0x%x bp=0x%p", 2227 epp, epp->ep_state, bp); 2228 2229 /* is this a read following a write with setup data? */ 2230 if (bp->b_flags & B_READ) { 2231 if (epp->ep_data) { 2232 int ep_len = epp->ep_data->b_wptr - 2233 epp->ep_data->b_rptr; 2234 int len = min(bp->b_bcount, ep_len); 2235 2236 bcopy(epp->ep_data->b_rptr, bp->b_un.b_addr, len); 2237 epp->ep_data->b_rptr += len; 2238 if ((epp->ep_data->b_wptr - epp->ep_data->b_rptr) == 2239 0) { 2240 freemsg(epp->ep_data); 2241 epp->ep_data = NULL; 2242 } 2243 bp->b_resid = bp->b_bcount - len; 2244 } else { 2245 bp->b_resid = bp->b_bcount; 2246 } 2247 2248 return (USB_SUCCESS); 2249 } 2250 2251 /* discard old data if any */ 2252 if (epp->ep_data) { 2253 freemsg(epp->ep_data); 2254 epp->ep_data = NULL; 2255 } 2256 2257 /* allocate and initialize request */ 2258 wLength = (setup[7] << 8) | setup[6]; 2259 reqp = usb_alloc_ctrl_req(ugenp->ug_dip, wLength, USB_FLAGS_NOSLEEP); 2260 if (reqp == NULL) { 2261 epp->ep_lcmd_status = USB_LC_STAT_NO_RESOURCES; 2262 2263 return (USB_NO_RESOURCES); 2264 } 2265 2266 /* assume an LE data stream */ 2267 reqp->ctrl_bmRequestType = setup[0]; 2268 reqp->ctrl_bRequest = setup[1]; 2269 reqp->ctrl_wValue = (setup[3] << 8) | setup[2]; 2270 reqp->ctrl_wIndex = (setup[5] << 8) | setup[4]; 2271 reqp->ctrl_wLength = wLength; 2272 reqp->ctrl_timeout = ugen_ctrl_timeout; 2273 reqp->ctrl_attributes = USB_ATTRS_AUTOCLEARING | 2274 USB_ATTRS_SHORT_XFER_OK; 2275 reqp->ctrl_cb = ugen_epx_ctrl_req_cb; 2276 reqp->ctrl_exc_cb = ugen_epx_ctrl_req_cb; 2277 reqp->ctrl_client_private = (usb_opaque_t)ugenp; 2278 2279 /* 2280 * is this a legal request? No accesses to device are 2281 * allowed if we don't own the device 2282 */ 2283 if (((reqp->ctrl_bmRequestType & USB_DEV_REQ_RCPT_MASK) == 2284 USB_DEV_REQ_RCPT_DEV) && 2285 (((reqp->ctrl_bmRequestType & USB_DEV_REQ_DIR_MASK) == 2286 USB_DEV_REQ_HOST_TO_DEV) && 2287 (usb_owns_device(ugenp->ug_dip) == B_FALSE))) { 2288 rval = USB_INVALID_PERM; 2289 epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2290 2291 goto fail; 2292 } 2293 2294 /* filter out set_cfg and set_if standard requests */ 2295 if ((reqp->ctrl_bmRequestType & USB_DEV_REQ_TYPE_MASK) == 2296 USB_DEV_REQ_TYPE_STANDARD) { 2297 switch (reqp->ctrl_bRequest) { 2298 case USB_REQ_SET_CFG: 2299 case USB_REQ_SET_IF: 2300 rval = USB_INVALID_REQUEST; 2301 epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2302 2303 goto fail; 2304 default: 2305 2306 break; 2307 } 2308 } 2309 2310 /* is this from host to device? */ 2311 if (((reqp->ctrl_bmRequestType & USB_DEV_REQ_DIR_MASK) == 2312 USB_DEV_REQ_HOST_TO_DEV) && reqp->ctrl_wLength) { 2313 if (((bp->b_bcount - UGEN_SETUP_PKT_SIZE) - wLength) != 0) { 2314 rval = USB_INVALID_REQUEST; 2315 epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2316 2317 goto fail; 2318 } 2319 bcopy(bp->b_un.b_addr + UGEN_SETUP_PKT_SIZE, 2320 reqp->ctrl_data->b_wptr, wLength); 2321 reqp->ctrl_data->b_wptr += wLength; 2322 } else if ((reqp->ctrl_bmRequestType & USB_DEV_REQ_DIR_MASK) == 2323 USB_DEV_REQ_DEV_TO_HOST) { 2324 if (bp->b_bcount != UGEN_SETUP_PKT_SIZE) { 2325 rval = USB_INVALID_REQUEST; 2326 epp->ep_lcmd_status = USB_LC_STAT_INVALID_REQ; 2327 2328 goto fail; 2329 } 2330 } 2331 2332 /* submit the request */ 2333 mutex_exit(&epp->ep_mutex); 2334 rval = usb_pipe_ctrl_xfer(epp->ep_ph, reqp, USB_FLAGS_NOSLEEP); 2335 mutex_enter(&epp->ep_mutex); 2336 if (rval != USB_SUCCESS) { 2337 epp->ep_lcmd_status = 2338 ugen_cr2lcstat(reqp->ctrl_completion_reason); 2339 2340 goto fail; 2341 } 2342 done: 2343 *wait = B_TRUE; 2344 2345 return (USB_SUCCESS); 2346 fail: 2347 *wait = B_FALSE; 2348 2349 usb_free_ctrl_req(reqp); 2350 2351 return (rval); 2352 } 2353 2354 2355 /* 2356 * callback for control requests, normal and exception completion 2357 */ 2358 static void 2359 ugen_epx_ctrl_req_cb(usb_pipe_handle_t ph, usb_ctrl_req_t *reqp) 2360 { 2361 ugen_state_t *ugenp = (ugen_state_t *)reqp->ctrl_client_private; 2362 ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2363 2364 if (epp == NULL) { 2365 epp = &ugenp->ug_ep[0]; 2366 } 2367 2368 mutex_enter(&epp->ep_mutex); 2369 2370 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2371 "ugen_epx_ctrl_req_cb:\n\t" 2372 "epp=0x%p state=0x%x ph=0x%p reqp=0x%p cr=%d cb=0x%x", 2373 epp, epp->ep_state, ph, reqp, reqp->ctrl_completion_reason, 2374 reqp->ctrl_cb_flags); 2375 2376 ASSERT((reqp->ctrl_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2377 2378 /* save any data for the next read */ 2379 switch (reqp->ctrl_completion_reason) { 2380 case USB_CR_OK: 2381 epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2382 2383 break; 2384 case USB_CR_PIPE_RESET: 2385 2386 break; 2387 default: 2388 epp->ep_lcmd_status = 2389 ugen_cr2lcstat(reqp->ctrl_completion_reason); 2390 if (epp->ep_bp) { 2391 bioerror(epp->ep_bp, EIO); 2392 } 2393 2394 break; 2395 } 2396 2397 if (reqp->ctrl_data) { 2398 ASSERT(epp->ep_data == NULL); 2399 epp->ep_data = reqp->ctrl_data; 2400 reqp->ctrl_data = NULL; 2401 } 2402 epp->ep_done++; 2403 cv_signal(&epp->ep_wait_cv); 2404 mutex_exit(&epp->ep_mutex); 2405 2406 usb_free_ctrl_req(reqp); 2407 2408 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2409 "ugen_epx_ctrl_req_cb: done"); 2410 } 2411 2412 2413 /* 2414 * handle bulk xfers 2415 */ 2416 static int 2417 ugen_epx_bulk_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2418 struct buf *bp, boolean_t *wait) 2419 { 2420 int rval; 2421 usb_bulk_req_t *reqp = usb_alloc_bulk_req(ugenp->ug_dip, 2422 bp->b_bcount, USB_FLAGS_NOSLEEP); 2423 2424 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2425 "ugen_epx_bulk_req: epp=0x%p state=0x%x bp=0x%p", 2426 epp, epp->ep_state, bp); 2427 2428 if (reqp == NULL) { 2429 epp->ep_lcmd_status = USB_LC_STAT_NO_RESOURCES; 2430 2431 return (USB_NO_RESOURCES); 2432 } 2433 2434 ASSERT(epp->ep_state & UGEN_EP_STATE_XS_OPEN); 2435 2436 /* 2437 * the transfer count is limited in minphys with what the HCD can 2438 * do 2439 */ 2440 reqp->bulk_len = bp->b_bcount; 2441 reqp->bulk_timeout = ugen_bulk_timeout; 2442 reqp->bulk_client_private = (usb_opaque_t)ugenp; 2443 reqp->bulk_attributes = USB_ATTRS_AUTOCLEARING; 2444 reqp->bulk_cb = ugen_epx_bulk_req_cb; 2445 reqp->bulk_exc_cb = ugen_epx_bulk_req_cb; 2446 2447 /* copy data into bp for OUT pipes */ 2448 if ((UGEN_XFER_DIR(epp) & USB_EP_DIR_IN) == 0) { 2449 bcopy(epp->ep_bp->b_un.b_addr, reqp->bulk_data->b_rptr, 2450 bp->b_bcount); 2451 reqp->bulk_data->b_wptr += bp->b_bcount; 2452 } else { 2453 reqp->bulk_attributes |= USB_ATTRS_SHORT_XFER_OK; 2454 } 2455 2456 mutex_exit(&epp->ep_mutex); 2457 if ((rval = usb_pipe_bulk_xfer(epp->ep_ph, reqp, 2458 USB_FLAGS_NOSLEEP)) != USB_SUCCESS) { 2459 mutex_enter(&epp->ep_mutex); 2460 epp->ep_lcmd_status = 2461 ugen_cr2lcstat(reqp->bulk_completion_reason); 2462 usb_free_bulk_req(reqp); 2463 bioerror(bp, EIO); 2464 } else { 2465 mutex_enter(&epp->ep_mutex); 2466 } 2467 *wait = (rval == USB_SUCCESS) ? B_TRUE : B_FALSE; 2468 2469 return (rval); 2470 } 2471 2472 2473 /* 2474 * normal and exception bulk request callback 2475 */ 2476 static void 2477 ugen_epx_bulk_req_cb(usb_pipe_handle_t ph, usb_bulk_req_t *reqp) 2478 { 2479 ugen_state_t *ugenp = (ugen_state_t *)reqp->bulk_client_private; 2480 ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2481 2482 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2483 "ugen_epx_bulk_req_cb: ph=0x%p reqp=0x%p cr=%d cb=0x%x", 2484 ph, reqp, reqp->bulk_completion_reason, reqp->bulk_cb_flags); 2485 2486 ASSERT((reqp->bulk_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2487 2488 /* epp might be NULL if we are closing the pipe */ 2489 if (epp) { 2490 mutex_enter(&epp->ep_mutex); 2491 if (epp->ep_bp && reqp->bulk_data) { 2492 int len = min(reqp->bulk_data->b_wptr - 2493 reqp->bulk_data->b_rptr, 2494 epp->ep_bp->b_bcount); 2495 if (UGEN_XFER_DIR(epp) & USB_EP_DIR_IN) { 2496 if (len) { 2497 bcopy(reqp->bulk_data->b_rptr, 2498 epp->ep_bp->b_un.b_addr, len); 2499 epp->ep_bp->b_resid = 2500 epp->ep_bp->b_bcount - len; 2501 } 2502 } else { 2503 epp->ep_bp->b_resid = 2504 epp->ep_bp->b_bcount - len; 2505 } 2506 } 2507 switch (reqp->bulk_completion_reason) { 2508 case USB_CR_OK: 2509 epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2510 2511 break; 2512 case USB_CR_PIPE_RESET: 2513 2514 break; 2515 default: 2516 epp->ep_lcmd_status = 2517 ugen_cr2lcstat(reqp->bulk_completion_reason); 2518 if (epp->ep_bp) { 2519 bioerror(epp->ep_bp, EIO); 2520 } 2521 } 2522 epp->ep_done++; 2523 cv_signal(&epp->ep_wait_cv); 2524 mutex_exit(&epp->ep_mutex); 2525 } 2526 2527 usb_free_bulk_req(reqp); 2528 } 2529 2530 2531 /* 2532 * handle intr IN xfers 2533 */ 2534 static int 2535 ugen_epx_intr_IN_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2536 struct buf *bp, boolean_t *wait) 2537 { 2538 int len = 0; 2539 int rval = USB_SUCCESS; 2540 2541 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2542 "ugen_epx_intr_IN_req: epp=0x%p state=0x%x bp=0x%p", 2543 epp, epp->ep_state, bp); 2544 2545 *wait = B_FALSE; 2546 2547 /* can we satisfy this read? */ 2548 if (epp->ep_data) { 2549 len = min(epp->ep_data->b_wptr - epp->ep_data->b_rptr, 2550 bp->b_bcount); 2551 } 2552 2553 /* 2554 * if polling not active, restart, and return failure 2555 * immediately unless one xfer mode has been requested 2556 * if there is some data, return a short read 2557 */ 2558 if ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON) == 0) { 2559 if (len == 0) { 2560 if (!epp->ep_one_xfer) { 2561 rval = USB_FAILURE; 2562 if (epp->ep_lcmd_status == 2563 USB_LC_STAT_NOERROR) { 2564 epp->ep_lcmd_status = 2565 USB_LC_STAT_INTR_BUF_FULL; 2566 } 2567 } 2568 if (ugen_epx_intr_IN_start_polling(ugenp, 2569 epp) != USB_SUCCESS) { 2570 epp->ep_lcmd_status = 2571 USB_LC_STAT_INTR_POLLING_FAILED; 2572 } 2573 if (epp->ep_one_xfer) { 2574 *wait = B_TRUE; 2575 } 2576 goto done; 2577 } else if (epp->ep_data && (len < bp->b_bcount)) { 2578 bcopy(epp->ep_data->b_rptr, bp->b_un.b_addr, len); 2579 bp->b_resid = bp->b_bcount - len; 2580 epp->ep_data->b_rptr += len; 2581 2582 goto done; 2583 } 2584 } 2585 2586 /* 2587 * if there is data or FNDELAY, return available data 2588 */ 2589 if ((len >= bp->b_bcount) || 2590 (epp->ep_xfer_oflag & (FNDELAY | FNONBLOCK))) { 2591 if (epp->ep_data) { 2592 bcopy(epp->ep_data->b_rptr, bp->b_un.b_addr, len); 2593 epp->ep_data->b_rptr += len; 2594 bp->b_resid = bp->b_bcount - len; 2595 } else { 2596 bp->b_resid = bp->b_bcount; 2597 } 2598 } else { 2599 /* otherwise just wait for data */ 2600 *wait = B_TRUE; 2601 } 2602 2603 done: 2604 if (epp->ep_data && (epp->ep_data->b_rptr == epp->ep_data->b_wptr)) { 2605 freemsg(epp->ep_data); 2606 epp->ep_data = NULL; 2607 } 2608 2609 if (*wait) { 2610 ASSERT(epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON); 2611 } 2612 2613 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2614 "ugen_epx_intr_IN_req end: rval=%d bcount=%lu len=%d data=0x%p", 2615 rval, bp->b_bcount, len, epp->ep_data); 2616 2617 return (rval); 2618 } 2619 2620 2621 /* 2622 * Start polling on interrupt endpoint, synchronously 2623 */ 2624 static int 2625 ugen_epx_intr_IN_start_polling(ugen_state_t *ugenp, ugen_ep_t *epp) 2626 { 2627 int rval = USB_FAILURE; 2628 usb_intr_req_t *reqp; 2629 usb_flags_t uflag; 2630 2631 /* 2632 * if polling is being stopped, we restart polling in the 2633 * interrrupt callback again 2634 */ 2635 if (epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED) { 2636 2637 return (rval); 2638 } 2639 if ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON) == 0) { 2640 USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2641 "ugen_epx_intr_IN_start_polling: epp=0x%p state=0x%x", 2642 epp, epp->ep_state); 2643 2644 epp->ep_state |= UGEN_EP_STATE_INTR_IN_POLLING_ON; 2645 mutex_exit(&epp->ep_mutex); 2646 2647 reqp = usb_alloc_intr_req(ugenp->ug_dip, 0, 2648 USB_FLAGS_SLEEP); 2649 reqp->intr_client_private = (usb_opaque_t)ugenp; 2650 2651 reqp->intr_attributes = USB_ATTRS_AUTOCLEARING | 2652 USB_ATTRS_SHORT_XFER_OK; 2653 mutex_enter(&epp->ep_mutex); 2654 if (epp->ep_one_xfer) { 2655 reqp->intr_attributes |= USB_ATTRS_ONE_XFER; 2656 uflag = USB_FLAGS_NOSLEEP; 2657 } else { 2658 uflag = USB_FLAGS_SLEEP; 2659 } 2660 mutex_exit(&epp->ep_mutex); 2661 2662 reqp->intr_len = epp->ep_descr.wMaxPacketSize; 2663 reqp->intr_cb = ugen_epx_intr_IN_req_cb; 2664 reqp->intr_exc_cb = ugen_epx_intr_IN_req_cb; 2665 2666 2667 if ((rval = usb_pipe_intr_xfer(epp->ep_ph, reqp, 2668 uflag)) != USB_SUCCESS) { 2669 USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2670 "ugen_epx_intr_IN_start_polling: failed %d", rval); 2671 usb_free_intr_req(reqp); 2672 } 2673 mutex_enter(&epp->ep_mutex); 2674 if (rval != USB_SUCCESS) { 2675 epp->ep_state &= ~UGEN_EP_STATE_INTR_IN_POLLING_ON; 2676 } 2677 } else { 2678 rval = USB_SUCCESS; 2679 } 2680 2681 return (rval); 2682 } 2683 2684 2685 /* 2686 * stop polling on an interrupt endpoint, asynchronously 2687 */ 2688 static void 2689 ugen_epx_intr_IN_stop_polling(ugen_state_t *ugenp, ugen_ep_t *epp) 2690 { 2691 if ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_ON) && 2692 ((epp->ep_state & UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED) == 0)) { 2693 2694 USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2695 "ugen_epx_intr_IN_stop_polling: epp=0x%p state=0x%x", 2696 epp, epp->ep_state); 2697 2698 epp->ep_state |= UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED; 2699 mutex_exit(&epp->ep_mutex); 2700 usb_pipe_stop_intr_polling(epp->ep_ph, USB_FLAGS_NOSLEEP); 2701 mutex_enter(&epp->ep_mutex); 2702 } 2703 } 2704 2705 2706 /* 2707 * poll management 2708 */ 2709 static void 2710 ugen_epx_intr_IN_poll_wakeup(ugen_state_t *ugenp, ugen_ep_t *epp) 2711 { 2712 if (epp->ep_state & UGEN_EP_STATE_INTR_IN_POLL_PENDING) { 2713 struct pollhead *phpp = &epp->ep_pollhead; 2714 2715 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2716 "ugen_epx_intr_IN_poll_wakeup: state=0x%x", epp->ep_state); 2717 2718 epp->ep_state &= ~UGEN_EP_STATE_INTR_IN_POLL_PENDING; 2719 mutex_exit(&epp->ep_mutex); 2720 pollwakeup(phpp, POLLIN); 2721 mutex_enter(&epp->ep_mutex); 2722 } 2723 } 2724 2725 2726 /* 2727 * callback functions for interrupt IN pipe 2728 */ 2729 static void 2730 ugen_epx_intr_IN_req_cb(usb_pipe_handle_t ph, usb_intr_req_t *reqp) 2731 { 2732 ugen_state_t *ugenp = (ugen_state_t *)reqp->intr_client_private; 2733 ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2734 2735 if (epp == NULL) { 2736 /* pipe is closing */ 2737 2738 goto done; 2739 } 2740 2741 mutex_enter(&epp->ep_mutex); 2742 2743 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2744 "ugen_epx_intr_IN_req_cb:\n\t" 2745 "epp=0x%p state=0x%x ph=0x%p reqp=0x%p cr=%d cb=0x%x len=%d", 2746 epp, epp->ep_state, ph, reqp, reqp->intr_completion_reason, 2747 reqp->intr_cb_flags, 2748 (reqp->intr_data == NULL) ? 0 : 2749 reqp->intr_data->b_wptr - reqp->intr_data->b_rptr); 2750 2751 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2752 2753 if (epp->ep_data && reqp->intr_data) { 2754 mblk_t *mp; 2755 2756 USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2757 "ep%x coalesce data", epp->ep_descr.bEndpointAddress); 2758 2759 /* coalesce the data into one mblk */ 2760 epp->ep_data->b_cont = reqp->intr_data; 2761 if ((mp = msgpullup(epp->ep_data, -1)) != NULL) { 2762 reqp->intr_data = NULL; 2763 freemsg(epp->ep_data); 2764 epp->ep_data = mp; 2765 } else { 2766 USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2767 "msgpullup failed, discard data"); 2768 epp->ep_data->b_cont = NULL; 2769 } 2770 } else if (reqp->intr_data) { 2771 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2772 "setting ep_data"); 2773 2774 epp->ep_data = reqp->intr_data; 2775 reqp->intr_data = NULL; 2776 } 2777 2778 switch (reqp->intr_completion_reason) { 2779 case USB_CR_OK: 2780 epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2781 2782 break; 2783 case USB_CR_PIPE_RESET: 2784 case USB_CR_STOPPED_POLLING: 2785 2786 break; 2787 default: 2788 epp->ep_lcmd_status = 2789 ugen_cr2lcstat(reqp->intr_completion_reason); 2790 USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2791 "ugen_exp_intr_cb_req: lcmd_status=0x%x", 2792 epp->ep_lcmd_status); 2793 2794 break; 2795 } 2796 2797 /* any non-zero completion reason stops polling */ 2798 if ((reqp->intr_completion_reason) || 2799 (epp->ep_one_xfer)) { 2800 epp->ep_state &= ~(UGEN_EP_STATE_INTR_IN_POLLING_ON | 2801 UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED); 2802 } 2803 2804 /* is there a poll pending? should we stop polling? */ 2805 if (epp->ep_data) { 2806 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2807 "ugen_epx_intr_IN_req_cb: data len=0x%x", 2808 epp->ep_data->b_wptr - epp->ep_data->b_rptr); 2809 2810 ugen_epx_intr_IN_poll_wakeup(ugenp, epp); 2811 2812 /* if there is no space left, stop polling */ 2813 if (epp->ep_data && 2814 ((epp->ep_data->b_wptr - epp->ep_data->b_rptr) >= 2815 epp->ep_buf_limit)) { 2816 ugen_epx_intr_IN_stop_polling(ugenp, epp); 2817 } 2818 } 2819 2820 if (reqp->intr_completion_reason && epp->ep_bp) { 2821 bioerror(epp->ep_bp, EIO); 2822 epp->ep_done++; 2823 cv_signal(&epp->ep_wait_cv); 2824 2825 /* can we satisfy the read now */ 2826 } else if (epp->ep_data && epp->ep_bp && 2827 (!epp->ep_done || epp->ep_one_xfer)) { 2828 boolean_t wait; 2829 2830 if ((ugen_epx_intr_IN_req(ugenp, epp, epp->ep_bp, &wait) == 2831 USB_SUCCESS) && (wait == B_FALSE)) { 2832 epp->ep_done++; 2833 cv_signal(&epp->ep_wait_cv); 2834 } 2835 } 2836 mutex_exit(&epp->ep_mutex); 2837 2838 done: 2839 usb_free_intr_req(reqp); 2840 } 2841 2842 2843 /* 2844 * handle intr OUT xfers 2845 */ 2846 static int 2847 ugen_epx_intr_OUT_req(ugen_state_t *ugenp, ugen_ep_t *epp, 2848 struct buf *bp, boolean_t *wait) 2849 { 2850 int rval = USB_SUCCESS; 2851 usb_intr_req_t *reqp; 2852 2853 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2854 "ugen_epx_intr_OUT_req: epp=0x%p state=0x%x bp=0x%p", 2855 epp, epp->ep_state, bp); 2856 2857 reqp = usb_alloc_intr_req(ugenp->ug_dip, bp->b_bcount, 2858 USB_FLAGS_NOSLEEP); 2859 if (reqp == NULL) { 2860 epp->ep_lcmd_status = USB_LC_STAT_NO_RESOURCES; 2861 2862 return (USB_NO_RESOURCES); 2863 } 2864 2865 ASSERT(epp->ep_state & UGEN_EP_STATE_XS_OPEN); 2866 2867 reqp->intr_timeout = ugen_intr_timeout; 2868 reqp->intr_client_private = (usb_opaque_t)ugenp; 2869 reqp->intr_len = bp->b_bcount; 2870 reqp->intr_attributes = USB_ATTRS_AUTOCLEARING; 2871 reqp->intr_cb = ugen_epx_intr_OUT_req_cb; 2872 reqp->intr_exc_cb = ugen_epx_intr_OUT_req_cb; 2873 2874 /* copy data from bp */ 2875 bcopy(epp->ep_bp->b_un.b_addr, reqp->intr_data->b_rptr, 2876 bp->b_bcount); 2877 reqp->intr_data->b_wptr += bp->b_bcount; 2878 2879 mutex_exit(&epp->ep_mutex); 2880 if ((rval = usb_pipe_intr_xfer(epp->ep_ph, reqp, 2881 USB_FLAGS_NOSLEEP)) != USB_SUCCESS) { 2882 mutex_enter(&epp->ep_mutex); 2883 epp->ep_lcmd_status = 2884 ugen_cr2lcstat(reqp->intr_completion_reason); 2885 usb_free_intr_req(reqp); 2886 bioerror(bp, EIO); 2887 } else { 2888 mutex_enter(&epp->ep_mutex); 2889 } 2890 *wait = (rval == USB_SUCCESS) ? B_TRUE : B_FALSE; 2891 2892 return (rval); 2893 } 2894 2895 2896 /* 2897 * callback functions for interrupt OUT pipe 2898 */ 2899 static void 2900 ugen_epx_intr_OUT_req_cb(usb_pipe_handle_t ph, usb_intr_req_t *reqp) 2901 { 2902 ugen_state_t *ugenp = (ugen_state_t *)reqp->intr_client_private; 2903 ugen_ep_t *epp = (ugen_ep_t *)usb_pipe_get_private(ph); 2904 2905 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 2906 "ugen_epx_intr_OUT_req_cb: ph=0x%p reqp=0x%p cr=%d cb=0x%x", 2907 ph, reqp, reqp->intr_completion_reason, reqp->intr_cb_flags); 2908 2909 ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0); 2910 2911 /* epp might be NULL if we are closing the pipe */ 2912 if (epp) { 2913 int len; 2914 2915 mutex_enter(&epp->ep_mutex); 2916 if (epp->ep_bp) { 2917 len = min(reqp->intr_data->b_wptr - 2918 reqp->intr_data->b_rptr, epp->ep_bp->b_bcount); 2919 2920 epp->ep_bp->b_resid = epp->ep_bp->b_bcount - len; 2921 2922 switch (reqp->intr_completion_reason) { 2923 case USB_CR_OK: 2924 epp->ep_lcmd_status = USB_LC_STAT_NOERROR; 2925 2926 break; 2927 case USB_CR_PIPE_RESET: 2928 2929 break; 2930 default: 2931 epp->ep_lcmd_status = 2932 ugen_cr2lcstat( 2933 reqp->intr_completion_reason); 2934 bioerror(epp->ep_bp, EIO); 2935 } 2936 } 2937 epp->ep_done++; 2938 cv_signal(&epp->ep_wait_cv); 2939 mutex_exit(&epp->ep_mutex); 2940 } 2941 2942 usb_free_intr_req(reqp); 2943 } 2944 2945 2946 /* 2947 * Endpoint status node management 2948 * 2949 * open/close an endpoint status node. 2950 * 2951 * Return values: errno 2952 */ 2953 static int 2954 ugen_eps_open(ugen_state_t *ugenp, dev_t dev, int flag) 2955 { 2956 ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 2957 int rval = EBUSY; 2958 2959 mutex_enter(&epp->ep_mutex); 2960 USB_DPRINTF_L4(UGEN_PRINT_STAT, ugenp->ug_log_hdl, 2961 "ugen_eps_open: dev=0x%lx flag=0x%x state=0x%x", 2962 dev, flag, epp->ep_state); 2963 2964 ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 2965 2966 /* only one open at the time */ 2967 if ((epp->ep_state & UGEN_EP_STATE_STAT_OPEN) == 0) { 2968 epp->ep_state |= UGEN_EP_STATE_STAT_OPEN; 2969 epp->ep_stat_oflag = flag; 2970 rval = 0; 2971 } 2972 mutex_exit(&epp->ep_mutex); 2973 2974 return (rval); 2975 } 2976 2977 2978 /* 2979 * close endpoint status 2980 */ 2981 static void 2982 ugen_eps_close(ugen_state_t *ugenp, dev_t dev, int flag) 2983 { 2984 ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, dev)]; 2985 2986 mutex_enter(&epp->ep_mutex); 2987 USB_DPRINTF_L4(UGEN_PRINT_STAT, ugenp->ug_log_hdl, 2988 "ugen_eps_close: dev=0x%lx flag=0x%x state=0x%x", 2989 dev, flag, epp->ep_state); 2990 2991 epp->ep_state &= ~(UGEN_EP_STATE_STAT_OPEN | 2992 UGEN_EP_STATE_INTR_IN_POLL_PENDING); 2993 epp->ep_one_xfer = B_FALSE; 2994 2995 USB_DPRINTF_L4(UGEN_PRINT_STAT, ugenp->ug_log_hdl, 2996 "ugen_eps_close: state=0x%x", epp->ep_state); 2997 2998 ASSERT(epp->ep_state & UGEN_EP_STATE_ACTIVE); 2999 mutex_exit(&epp->ep_mutex); 3000 } 3001 3002 3003 /* 3004 * return status info 3005 * 3006 * Return values: errno 3007 */ 3008 static int 3009 ugen_eps_req(ugen_state_t *ugenp, struct buf *bp) 3010 { 3011 ugen_ep_t *epp = &ugenp->ug_ep[UGEN_MINOR_EPIDX(ugenp, bp->b_edev)]; 3012 3013 mutex_enter(&epp->ep_mutex); 3014 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3015 "ugen_eps_req: bp=0x%p lcmd_status=0x%x bcount=%lu", 3016 bp, epp->ep_lcmd_status, bp->b_bcount); 3017 3018 if (bp->b_flags & B_READ) { 3019 int len = min(sizeof (epp->ep_lcmd_status), bp->b_bcount); 3020 if (len) { 3021 bcopy(&epp->ep_lcmd_status, bp->b_un.b_addr, len); 3022 } 3023 bp->b_resid = bp->b_bcount - len; 3024 } else { 3025 USB_DPRINTF_L3(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3026 "ugen_eps_req: control=0x%x", 3027 *((char *)(bp->b_un.b_addr))); 3028 3029 if (epp->ep_state & UGEN_EP_STATE_XFER_OPEN) { 3030 USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3031 "ugen_eps_req: cannot change one xfer mode if " 3032 "endpoint is open"); 3033 3034 mutex_exit(&epp->ep_mutex); 3035 3036 return (EINVAL); 3037 } 3038 3039 if ((epp->ep_descr.bmAttributes & USB_EP_ATTR_INTR) && 3040 (epp->ep_descr.bEndpointAddress & USB_EP_DIR_IN)) { 3041 epp->ep_one_xfer = (*((char *)(bp->b_un.b_addr)) & 3042 USB_EP_INTR_ONE_XFER) ? B_TRUE : B_FALSE; 3043 } else { 3044 USB_DPRINTF_L2(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3045 "ugen_eps_req: not an interrupt endpoint"); 3046 3047 mutex_exit(&epp->ep_mutex); 3048 3049 return (EINVAL); 3050 } 3051 3052 bp->b_resid = bp->b_bcount - 1; 3053 } 3054 mutex_exit(&epp->ep_mutex); 3055 3056 return (0); 3057 } 3058 3059 3060 /* 3061 * device status node management 3062 */ 3063 static int 3064 ugen_ds_init(ugen_state_t *ugenp) 3065 { 3066 cv_init(&ugenp->ug_ds.dev_wait_cv, NULL, CV_DRIVER, NULL); 3067 3068 /* Create devstat minor node for this instance */ 3069 if (ugen_ds_minor_nodes_create(ugenp) != USB_SUCCESS) { 3070 USB_DPRINTF_L2(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 3071 "ugen_create_dev_stat_minor_nodes failed"); 3072 3073 return (USB_FAILURE); 3074 } 3075 3076 3077 return (USB_SUCCESS); 3078 } 3079 3080 3081 static void 3082 ugen_ds_destroy(ugen_state_t *ugenp) 3083 { 3084 cv_destroy(&ugenp->ug_ds.dev_wait_cv); 3085 } 3086 3087 3088 /* 3089 * open devstat minor node 3090 * 3091 * Return values: errno 3092 */ 3093 static int 3094 ugen_ds_open(ugen_state_t *ugenp, dev_t dev, int flag) 3095 { 3096 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3097 "ugen_ds_open: dev=0x%lx flag=0x%x", dev, flag); 3098 3099 mutex_enter(&ugenp->ug_mutex); 3100 if ((ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_ACTIVE) == 0) { 3101 /* 3102 * first read on device node should return status 3103 */ 3104 ugenp->ug_ds.dev_stat |= UGEN_DEV_STATUS_CHANGED | 3105 UGEN_DEV_STATUS_ACTIVE; 3106 ugenp->ug_ds.dev_oflag = flag; 3107 mutex_exit(&ugenp->ug_mutex); 3108 3109 return (0); 3110 } else { 3111 mutex_exit(&ugenp->ug_mutex); 3112 3113 return (EBUSY); 3114 } 3115 } 3116 3117 3118 static void 3119 ugen_ds_close(ugen_state_t *ugenp, dev_t dev, int flag) 3120 { 3121 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3122 "ugen_ds_close: dev=0x%lx flag=0x%x", dev, flag); 3123 3124 mutex_enter(&ugenp->ug_mutex); 3125 ugenp->ug_ds.dev_stat = UGEN_DEV_STATUS_INACTIVE; 3126 mutex_exit(&ugenp->ug_mutex); 3127 } 3128 3129 3130 /* 3131 * request for devstat 3132 * 3133 * Return values: errno 3134 */ 3135 static int 3136 ugen_ds_req(ugen_state_t *ugenp, struct buf *bp) 3137 { 3138 int len = min(sizeof (ugenp->ug_ds.dev_state), bp->b_bcount); 3139 3140 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3141 "ugen_ds_req: bp=0x%p", bp); 3142 3143 mutex_enter(&ugenp->ug_mutex); 3144 if ((ugenp->ug_ds.dev_oflag & (FNDELAY | FNONBLOCK)) == 0) { 3145 while ((ugenp->ug_ds.dev_stat & 3146 UGEN_DEV_STATUS_CHANGED) == 0) { 3147 if (cv_wait_sig(&ugenp->ug_ds.dev_wait_cv, 3148 &ugenp->ug_mutex) <= 0) { 3149 mutex_exit(&ugenp->ug_mutex); 3150 3151 return (EINTR); 3152 } 3153 } 3154 } else if ((ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_CHANGED) == 3155 0) { 3156 bp->b_resid = bp->b_bcount; 3157 mutex_exit(&ugenp->ug_mutex); 3158 3159 return (0); 3160 } 3161 3162 ugenp->ug_ds.dev_stat &= ~UGEN_DEV_STATUS_CHANGED; 3163 switch (ugenp->ug_dev_state) { 3164 case USB_DEV_ONLINE: 3165 ugenp->ug_ds.dev_state = USB_DEV_STAT_ONLINE; 3166 3167 break; 3168 case USB_DEV_DISCONNECTED: 3169 ugenp->ug_ds.dev_state = USB_DEV_STAT_DISCONNECTED; 3170 3171 break; 3172 case USB_DEV_SUSPENDED: 3173 case USB_UGEN_DEV_UNAVAILABLE_RESUME: 3174 ugenp->ug_ds.dev_state = USB_DEV_STAT_RESUMED; 3175 3176 break; 3177 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 3178 default: 3179 ugenp->ug_ds.dev_state = USB_DEV_STAT_UNAVAILABLE; 3180 3181 break; 3182 } 3183 3184 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3185 "ugen_ds_req: dev_state=0x%x dev_stat=0x%x", 3186 ugenp->ug_dev_state, ugenp->ug_ds.dev_stat); 3187 3188 bcopy(&ugenp->ug_ds.dev_state, bp->b_un.b_addr, len); 3189 bp->b_resid = bp->b_bcount - len; 3190 3191 mutex_exit(&ugenp->ug_mutex); 3192 3193 return (0); 3194 } 3195 3196 3197 static void 3198 ugen_ds_change(ugen_state_t *ugenp) 3199 { 3200 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3201 "ugen_ds_change:"); 3202 3203 ugenp->ug_ds.dev_stat |= UGEN_DEV_STATUS_CHANGED; 3204 cv_signal(&ugenp->ug_ds.dev_wait_cv); 3205 } 3206 3207 3208 /* 3209 * poll management 3210 */ 3211 static void 3212 ugen_ds_poll_wakeup(ugen_state_t *ugenp) 3213 { 3214 USB_DPRINTF_L4(UGEN_PRINT_XFER, ugenp->ug_log_hdl, 3215 "ugen_ds_poll_wakeup:"); 3216 3217 if (ugenp->ug_ds.dev_stat & UGEN_DEV_STATUS_POLL_PENDING) { 3218 struct pollhead *phpp = &ugenp->ug_ds.dev_pollhead; 3219 ugenp->ug_ds.dev_stat &= ~UGEN_DEV_STATUS_POLL_PENDING; 3220 mutex_exit(&ugenp->ug_mutex); 3221 pollwakeup(phpp, POLLIN); 3222 mutex_enter(&ugenp->ug_mutex); 3223 } 3224 } 3225 3226 3227 /* 3228 * minor node management: 3229 */ 3230 static int 3231 ugen_ds_minor_nodes_create(ugen_state_t *ugenp) 3232 { 3233 char node_name[32]; 3234 int vid = ugenp->ug_dev_data->dev_descr->idVendor; 3235 int pid = ugenp->ug_dev_data->dev_descr->idProduct; 3236 minor_t minor; 3237 int minor_index; 3238 int owns_device = (usb_owns_device(ugenp->ug_dip) ? 3239 UGEN_OWNS_DEVICE : 0); 3240 3241 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3242 "ugen_ds_minor_nodes_create: idx shift=%d inst shift=%d", 3243 UGEN_MINOR_IDX_SHIFT(ugenp), 3244 UGEN_MINOR_INSTANCE_SHIFT(ugenp)); 3245 3246 if (ugenp->ug_instance >= UGEN_MINOR_INSTANCE_LIMIT(ugenp)) { 3247 USB_DPRINTF_L0(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3248 "instance number too high (%d)", ugenp->ug_instance); 3249 3250 return (USB_FAILURE); 3251 } 3252 3253 /* create devstat minor node */ 3254 if (owns_device) { 3255 (void) sprintf(node_name, "%x.%x.devstat", vid, pid); 3256 } else { 3257 (void) sprintf(node_name, "%x.%x.if%ddevstat", vid, pid, 3258 ugenp->ug_dev_data->dev_curr_if); 3259 } 3260 3261 minor_index = ugen_minor_index_create(ugenp, 3262 (UGEN_MINOR_DEV_STAT_NODE | owns_device) << 3263 UGEN_MINOR_IDX_SHIFT(ugenp)); 3264 3265 if (minor_index < 0) { 3266 USB_DPRINTF_L0(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3267 "too many minor nodes"); 3268 3269 return (USB_FAILURE); 3270 } 3271 minor = (minor_index << UGEN_MINOR_IDX_SHIFT(ugenp)) | 3272 ugenp->ug_instance << UGEN_MINOR_INSTANCE_SHIFT(ugenp); 3273 3274 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3275 "minor=0x%x minor_index=%d name=%s", 3276 minor, minor_index, node_name); 3277 3278 ASSERT(minor < L_MAXMIN); 3279 3280 if ((ddi_create_minor_node(ugenp->ug_dip, node_name, 3281 S_IFCHR, minor, DDI_NT_UGEN, 0)) != DDI_SUCCESS) { 3282 3283 return (USB_FAILURE); 3284 } 3285 3286 ugen_store_devt(ugenp, minor); 3287 3288 return (USB_SUCCESS); 3289 } 3290 3291 3292 /* 3293 * utility functions: 3294 * 3295 * conversion from completion reason to USB_LC_STAT_* 3296 */ 3297 static struct ugen_cr2lcstat_entry { 3298 int cr; 3299 int lcstat; 3300 } ugen_cr2lcstat_table[] = { 3301 { USB_CR_OK, USB_LC_STAT_NOERROR }, 3302 { USB_CR_CRC, USB_LC_STAT_CRC }, 3303 { USB_CR_BITSTUFFING, USB_LC_STAT_BITSTUFFING }, 3304 { USB_CR_DATA_TOGGLE_MM, USB_LC_STAT_DATA_TOGGLE_MM }, 3305 { USB_CR_STALL, USB_LC_STAT_STALL }, 3306 { USB_CR_DEV_NOT_RESP, USB_LC_STAT_DEV_NOT_RESP }, 3307 { USB_CR_PID_CHECKFAILURE, USB_LC_STAT_PID_CHECKFAILURE }, 3308 { USB_CR_UNEXP_PID, USB_LC_STAT_UNEXP_PID }, 3309 { USB_CR_DATA_OVERRUN, USB_LC_STAT_DATA_OVERRUN }, 3310 { USB_CR_DATA_UNDERRUN, USB_LC_STAT_DATA_UNDERRUN }, 3311 { USB_CR_BUFFER_OVERRUN, USB_LC_STAT_BUFFER_OVERRUN }, 3312 { USB_CR_BUFFER_UNDERRUN, USB_LC_STAT_BUFFER_UNDERRUN }, 3313 { USB_CR_TIMEOUT, USB_LC_STAT_TIMEOUT }, 3314 { USB_CR_NOT_ACCESSED, USB_LC_STAT_NOT_ACCESSED }, 3315 { USB_CR_NO_RESOURCES, USB_LC_STAT_NO_BANDWIDTH }, 3316 { USB_CR_UNSPECIFIED_ERR, USB_LC_STAT_UNSPECIFIED_ERR }, 3317 { USB_CR_STOPPED_POLLING, USB_LC_STAT_HW_ERR }, 3318 { USB_CR_PIPE_CLOSING, USB_LC_STAT_UNSPECIFIED_ERR }, 3319 { USB_CR_PIPE_RESET, USB_LC_STAT_UNSPECIFIED_ERR }, 3320 { USB_CR_NOT_SUPPORTED, USB_LC_STAT_UNSPECIFIED_ERR }, 3321 { USB_CR_FLUSHED, USB_LC_STAT_UNSPECIFIED_ERR } 3322 }; 3323 3324 #define UGEN_CR2LCSTAT_TABLE_SIZE (sizeof (ugen_cr2lcstat_table) / \ 3325 sizeof (struct ugen_cr2lcstat_entry)) 3326 static int 3327 ugen_cr2lcstat(int cr) 3328 { 3329 int i; 3330 3331 for (i = 0; i < UGEN_CR2LCSTAT_TABLE_SIZE; i++) { 3332 if (ugen_cr2lcstat_table[i].cr == cr) { 3333 3334 return (ugen_cr2lcstat_table[i].lcstat); 3335 } 3336 } 3337 3338 return (USB_LC_STAT_UNSPECIFIED_ERR); 3339 } 3340 3341 3342 /* 3343 * create and lookup minor index 3344 */ 3345 static int 3346 ugen_minor_index_create(ugen_state_t *ugenp, ugen_minor_t minor) 3347 { 3348 int i; 3349 3350 /* check if already in the table */ 3351 for (i = 1; i < ugenp->ug_minor_node_table_index; i++) { 3352 if (ugenp->ug_minor_node_table[i] == minor) { 3353 3354 return (-1); 3355 } 3356 } 3357 if (ugenp->ug_minor_node_table_index < 3358 (ugenp->ug_minor_node_table_size/sizeof (ugen_minor_t))) { 3359 ugenp->ug_minor_node_table[ugenp-> 3360 ug_minor_node_table_index] = minor; 3361 3362 USB_DPRINTF_L4(UGEN_PRINT_ATTA, ugenp->ug_log_hdl, 3363 "ugen_minor_index_create: %d: 0x%lx", 3364 ugenp->ug_minor_node_table_index, 3365 minor); 3366 3367 return (ugenp->ug_minor_node_table_index++); 3368 } else { 3369 3370 return (-1); 3371 } 3372 } 3373 3374 3375 static ugen_minor_t 3376 ugen_devt2minor(ugen_state_t *ugenp, dev_t dev) 3377 { 3378 USB_DPRINTF_L4(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3379 "ugen_devt2minor: minorindex=%d, minor=0x%" PRIx64, 3380 UGEN_MINOR_GET_IDX(ugenp, dev), 3381 ugenp->ug_minor_node_table[UGEN_MINOR_GET_IDX(ugenp, dev)]); 3382 3383 ASSERT(UGEN_MINOR_GET_IDX(ugenp, dev) < 3384 ugenp->ug_minor_node_table_index); 3385 3386 return (ugenp->ug_minor_node_table[UGEN_MINOR_GET_IDX(ugenp, dev)]); 3387 } 3388 3389 3390 static int 3391 ugen_is_valid_minor_node(ugen_state_t *ugenp, dev_t dev) 3392 { 3393 int idx = UGEN_MINOR_GET_IDX(ugenp, dev); 3394 3395 if ((idx < ugenp->ug_minor_node_table_index) && 3396 (idx > 0)) { 3397 3398 return (USB_SUCCESS); 3399 } 3400 USB_DPRINTF_L2(UGEN_PRINT_CBOPS, ugenp->ug_log_hdl, 3401 "ugen_is_valid_minor_node: invalid minorindex=%d", idx); 3402 3403 return (USB_FAILURE); 3404 } 3405 3406 3407 static void 3408 ugen_minor_node_table_create(ugen_state_t *ugenp) 3409 { 3410 size_t size = sizeof (ugen_minor_t) * UGEN_MINOR_IDX_LIMIT(ugenp); 3411 3412 /* allocate the max table size needed, we reduce later */ 3413 ugenp->ug_minor_node_table = kmem_zalloc(size, KM_SLEEP); 3414 ugenp->ug_minor_node_table_size = size; 3415 ugenp->ug_minor_node_table_index = 1; 3416 } 3417 3418 3419 static void 3420 ugen_minor_node_table_shrink(ugen_state_t *ugenp) 3421 { 3422 /* reduce the table size to save some memory */ 3423 if (ugenp->ug_minor_node_table_index < UGEN_MINOR_IDX_LIMIT(ugenp)) { 3424 size_t newsize = sizeof (ugen_minor_t) * 3425 ugenp->ug_minor_node_table_index; 3426 ugen_minor_t *buf = kmem_zalloc(newsize, KM_SLEEP); 3427 3428 bcopy(ugenp->ug_minor_node_table, buf, newsize); 3429 kmem_free(ugenp->ug_minor_node_table, 3430 ugenp->ug_minor_node_table_size); 3431 ugenp->ug_minor_node_table = buf; 3432 ugenp->ug_minor_node_table_size = newsize; 3433 } 3434 } 3435 3436 3437 static void 3438 ugen_minor_node_table_destroy(ugen_state_t *ugenp) 3439 { 3440 if (ugenp->ug_minor_node_table) { 3441 kmem_free(ugenp->ug_minor_node_table, 3442 ugenp->ug_minor_node_table_size); 3443 } 3444 } 3445 3446 3447 static void 3448 ugen_check_mask(uint_t mask, uint_t *shift, uint_t *limit) 3449 { 3450 uint_t i, j; 3451 3452 for (i = 0; i < UGEN_MINOR_NODE_SIZE; i++) { 3453 if ((1 << i) & mask) { 3454 3455 break; 3456 } 3457 } 3458 3459 for (j = i; j < UGEN_MINOR_NODE_SIZE; j++) { 3460 if (((1 << j) & mask) == 0) { 3461 3462 break; 3463 } 3464 } 3465 3466 *limit = (i == j) ? 0 : 1 << (j - i); 3467 *shift = i; 3468 } 3469 3470 3471 3472 /* 3473 * power management: 3474 * 3475 * ugen_pm_init: 3476 * Initialize power management and remote wakeup functionality. 3477 * No mutex is necessary in this function as it's called only by attach. 3478 */ 3479 static void 3480 ugen_pm_init(ugen_state_t *ugenp) 3481 { 3482 dev_info_t *dip = ugenp->ug_dip; 3483 ugen_power_t *ugenpm; 3484 3485 USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3486 "ugen_pm_init:"); 3487 3488 /* Allocate the state structure */ 3489 ugenpm = kmem_zalloc(sizeof (ugen_power_t), KM_SLEEP); 3490 3491 mutex_enter(&ugenp->ug_mutex); 3492 ugenp->ug_pm = ugenpm; 3493 ugenpm->pwr_wakeup_enabled = B_FALSE; 3494 ugenpm->pwr_current = USB_DEV_OS_FULL_PWR; 3495 mutex_exit(&ugenp->ug_mutex); 3496 3497 /* 3498 * If remote wakeup is not available you may not want to do 3499 * power management. 3500 */ 3501 if (ugen_enable_pm || usb_handle_remote_wakeup(dip, 3502 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) { 3503 if (usb_create_pm_components(dip, 3504 &ugenpm->pwr_states) == USB_SUCCESS) { 3505 USB_DPRINTF_L4(UGEN_PRINT_PM, 3506 ugenp->ug_log_hdl, 3507 "ugen_pm_init: " 3508 "created PM components"); 3509 3510 mutex_enter(&ugenp->ug_mutex); 3511 ugenpm->pwr_wakeup_enabled = B_TRUE; 3512 mutex_exit(&ugenp->ug_mutex); 3513 3514 if (pm_raise_power(dip, 0, 3515 USB_DEV_OS_FULL_PWR) != DDI_SUCCESS) { 3516 USB_DPRINTF_L2(UGEN_PRINT_PM, 3517 ugenp->ug_log_hdl, 3518 "ugen_pm_init: " 3519 "raising power failed"); 3520 } 3521 } else { 3522 USB_DPRINTF_L2(UGEN_PRINT_PM, 3523 ugenp->ug_log_hdl, 3524 "ugen_pm_init: " 3525 "create_pm_comps failed"); 3526 } 3527 } else { 3528 USB_DPRINTF_L2(UGEN_PRINT_PM, 3529 ugenp->ug_log_hdl, "ugen_pm_init: " 3530 "failure enabling remote wakeup"); 3531 } 3532 3533 USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3534 "ugen_pm_init: end"); 3535 } 3536 3537 3538 /* 3539 * ugen_pm_destroy: 3540 * Shut down and destroy power management and remote wakeup functionality. 3541 */ 3542 static void 3543 ugen_pm_destroy(ugen_state_t *ugenp) 3544 { 3545 dev_info_t *dip = ugenp->ug_dip; 3546 3547 USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3548 "ugen_pm_destroy:"); 3549 3550 if (ugenp->ug_pm) { 3551 mutex_exit(&ugenp->ug_mutex); 3552 ugen_pm_busy_component(ugenp); 3553 mutex_enter(&ugenp->ug_mutex); 3554 3555 if ((ugenp->ug_pm->pwr_wakeup_enabled) && 3556 (ugenp->ug_dev_state != USB_DEV_DISCONNECTED)) { 3557 int rval; 3558 3559 mutex_exit(&ugenp->ug_mutex); 3560 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 3561 3562 if ((rval = usb_handle_remote_wakeup(dip, 3563 USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) { 3564 USB_DPRINTF_L4(UGEN_PRINT_PM, 3565 ugenp->ug_log_hdl, "ugen_pm_destroy: " 3566 "disabling rmt wakeup: rval=%d", rval); 3567 } 3568 /* 3569 * Since remote wakeup is disabled now, 3570 * no one can raise power 3571 * and get to device once power is lowered here. 3572 */ 3573 } else { 3574 mutex_exit(&ugenp->ug_mutex); 3575 } 3576 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF); 3577 ugen_pm_idle_component(ugenp); 3578 3579 mutex_enter(&ugenp->ug_mutex); 3580 kmem_free(ugenp->ug_pm, sizeof (ugen_power_t)); 3581 ugenp->ug_pm = NULL; 3582 } 3583 } 3584 3585 3586 /* 3587 * ugen_power : 3588 * Power entry point, the workhorse behind pm_raise_power, pm_lower_power, 3589 * usb_req_raise_power and usb_req_lower_power. 3590 */ 3591 /*ARGSUSED*/ 3592 int 3593 usb_ugen_power(usb_ugen_hdl_t usb_ugen_hdl, int comp, int level) 3594 { 3595 ugen_power_t *pm; 3596 int rval = USB_FAILURE; 3597 usb_ugen_hdl_impl_t *usb_ugen_hdl_impl = 3598 (usb_ugen_hdl_impl_t *)usb_ugen_hdl; 3599 ugen_state_t *ugenp; 3600 dev_info_t *dip; 3601 3602 if (usb_ugen_hdl == NULL) { 3603 3604 return (USB_FAILURE); 3605 } 3606 3607 ugenp = usb_ugen_hdl_impl->hdl_ugenp; 3608 dip = ugenp->ug_dip; 3609 3610 if (ugenp->ug_pm == NULL) { 3611 3612 return (USB_SUCCESS); 3613 } 3614 3615 USB_DPRINTF_L4(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3616 "usb_ugen_power: level=%d", level); 3617 3618 (void) usb_serialize_access(ugenp->ug_ser_cookie, 3619 USB_WAIT, 0); 3620 /* 3621 * If we are disconnected/suspended, return success. Note that if we 3622 * return failure, bringing down the system will hang when 3623 * PM tries to power up all devices 3624 */ 3625 mutex_enter(&ugenp->ug_mutex); 3626 switch (ugenp->ug_dev_state) { 3627 case USB_DEV_ONLINE: 3628 3629 break; 3630 case USB_DEV_DISCONNECTED: 3631 case USB_DEV_SUSPENDED: 3632 case USB_UGEN_DEV_UNAVAILABLE_RESUME: 3633 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 3634 default: 3635 USB_DPRINTF_L2(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3636 "ugen_power: disconnected/suspended " 3637 "dev_state=%d", ugenp->ug_dev_state); 3638 rval = USB_SUCCESS; 3639 3640 goto done; 3641 } 3642 3643 pm = ugenp->ug_pm; 3644 3645 /* Check if we are transitioning to a legal power level */ 3646 if (USB_DEV_PWRSTATE_OK(pm->pwr_states, level)) { 3647 USB_DPRINTF_L2(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3648 "ugen_power: illegal power level=%d " 3649 "pwr_states: 0x%x", level, pm->pwr_states); 3650 3651 goto done; 3652 } 3653 3654 switch (level) { 3655 case USB_DEV_OS_PWR_OFF : 3656 switch (ugenp->ug_dev_state) { 3657 case USB_DEV_ONLINE: 3658 /* Deny the powerdown request if the device is busy */ 3659 if (ugenp->ug_pm->pwr_busy != 0) { 3660 3661 break; 3662 } 3663 ASSERT(ugenp->ug_open_count == 0); 3664 ASSERT(ugenp->ug_pending_cmds == 0); 3665 ugenp->ug_pm->pwr_current = USB_DEV_OS_PWR_OFF; 3666 mutex_exit(&ugenp->ug_mutex); 3667 3668 /* Issue USB D3 command to the device here */ 3669 rval = usb_set_device_pwrlvl3(dip); 3670 mutex_enter(&ugenp->ug_mutex); 3671 3672 break; 3673 default: 3674 rval = USB_SUCCESS; 3675 3676 break; 3677 } 3678 break; 3679 case USB_DEV_OS_FULL_PWR : 3680 /* 3681 * PM framework tries to put us in full power during system 3682 * shutdown. 3683 */ 3684 switch (ugenp->ug_dev_state) { 3685 case USB_UGEN_DEV_UNAVAILABLE_RESUME: 3686 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT: 3687 3688 break; 3689 default: 3690 ugenp->ug_dev_state = USB_DEV_ONLINE; 3691 3692 /* wakeup devstat reads and polls */ 3693 ugen_ds_change(ugenp); 3694 ugen_ds_poll_wakeup(ugenp); 3695 3696 break; 3697 } 3698 ugenp->ug_pm->pwr_current = USB_DEV_OS_FULL_PWR; 3699 mutex_exit(&ugenp->ug_mutex); 3700 rval = usb_set_device_pwrlvl0(dip); 3701 mutex_enter(&ugenp->ug_mutex); 3702 3703 break; 3704 default: 3705 /* Levels 1 and 2 are not supported to keep it simple. */ 3706 USB_DPRINTF_L2(UGEN_PRINT_PM, ugenp->ug_log_hdl, 3707 "ugen_power: power level %d not supported", level); 3708 3709 break; 3710 } 3711 done: 3712 mutex_exit(&ugenp->ug_mutex); 3713 usb_release_access(ugenp->ug_ser_cookie); 3714 3715 return (rval); 3716 } 3717 3718 3719 static void 3720 ugen_pm_busy_component(ugen_state_t *ugen_statep) 3721 { 3722 ASSERT(!mutex_owned(&ugen_statep->ug_mutex)); 3723 3724 if (ugen_statep->ug_pm != NULL) { 3725 mutex_enter(&ugen_statep->ug_mutex); 3726 ugen_statep->ug_pm->pwr_busy++; 3727 3728 USB_DPRINTF_L4(UGEN_PRINT_PM, ugen_statep->ug_log_hdl, 3729 "ugen_pm_busy_component: %d", ugen_statep->ug_pm->pwr_busy); 3730 3731 mutex_exit(&ugen_statep->ug_mutex); 3732 if (pm_busy_component(ugen_statep->ug_dip, 0) != DDI_SUCCESS) { 3733 mutex_enter(&ugen_statep->ug_mutex); 3734 ugen_statep->ug_pm->pwr_busy--; 3735 3736 USB_DPRINTF_L2(UGEN_PRINT_PM, ugen_statep->ug_log_hdl, 3737 "ugen_pm_busy_component failed: %d", 3738 ugen_statep->ug_pm->pwr_busy); 3739 3740 mutex_exit(&ugen_statep->ug_mutex); 3741 } 3742 } 3743 } 3744 3745 3746 static void 3747 ugen_pm_idle_component(ugen_state_t *ugen_statep) 3748 { 3749 ASSERT(!mutex_owned(&ugen_statep->ug_mutex)); 3750 3751 if (ugen_statep->ug_pm != NULL) { 3752 if (pm_idle_component(ugen_statep->ug_dip, 0) == DDI_SUCCESS) { 3753 mutex_enter(&ugen_statep->ug_mutex); 3754 ASSERT(ugen_statep->ug_pm->pwr_busy > 0); 3755 ugen_statep->ug_pm->pwr_busy--; 3756 3757 USB_DPRINTF_L4(UGEN_PRINT_PM, ugen_statep->ug_log_hdl, 3758 "ugen_pm_idle_component: %d", 3759 ugen_statep->ug_pm->pwr_busy); 3760 3761 mutex_exit(&ugen_statep->ug_mutex); 3762 } 3763 } 3764 } 3765 3766 3767 /* 3768 * devt lookup support 3769 * In ugen_strategy and ugen_minphys, we only have the devt and need 3770 * the ugen_state pointer. Since we don't know instance mask, we can't 3771 * easily derive a softstate pointer. Therefore, we use a list 3772 */ 3773 static void 3774 ugen_store_devt(ugen_state_t *ugenp, minor_t minor) 3775 { 3776 ugen_devt_list_entry_t *e = kmem_zalloc( 3777 sizeof (ugen_devt_list_entry_t), KM_SLEEP); 3778 ugen_devt_list_entry_t *t; 3779 3780 mutex_enter(&ugen_devt_list_mutex); 3781 e->list_dev = makedevice(ddi_driver_major(ugenp->ug_dip), minor); 3782 e->list_state = ugenp; 3783 3784 t = ugen_devt_list.list_next; 3785 3786 /* check if the entry is already in the list */ 3787 while (t) { 3788 ASSERT(t->list_dev != e->list_dev); 3789 t = t->list_next; 3790 } 3791 3792 /* add to the head of the list */ 3793 e->list_next = ugen_devt_list.list_next; 3794 if (ugen_devt_list.list_next) { 3795 ugen_devt_list.list_next->list_prev = e; 3796 } 3797 ugen_devt_list.list_next = e; 3798 mutex_exit(&ugen_devt_list_mutex); 3799 } 3800 3801 3802 static ugen_state_t * 3803 ugen_devt2state(dev_t dev) 3804 { 3805 ugen_devt_list_entry_t *t; 3806 ugen_state_t *ugenp = NULL; 3807 int index, count; 3808 3809 mutex_enter(&ugen_devt_list_mutex); 3810 3811 for (index = ugen_devt_cache_index, count = 0; 3812 count < UGEN_DEVT_CACHE_SIZE; count++) { 3813 if (ugen_devt_cache[index].cache_dev == dev) { 3814 ugen_devt_cache[index].cache_hit++; 3815 ugenp = ugen_devt_cache[index].cache_state; 3816 3817 mutex_exit(&ugen_devt_list_mutex); 3818 3819 return (ugenp); 3820 } 3821 index++; 3822 index %= UGEN_DEVT_CACHE_SIZE; 3823 } 3824 3825 t = ugen_devt_list.list_next; 3826 3827 while (t) { 3828 if (t->list_dev == dev) { 3829 ugenp = t->list_state; 3830 ugen_devt_cache_index++; 3831 ugen_devt_cache_index %= UGEN_DEVT_CACHE_SIZE; 3832 ugen_devt_cache[ugen_devt_cache_index].cache_dev = dev; 3833 ugen_devt_cache[ugen_devt_cache_index].cache_state = 3834 ugenp; 3835 mutex_exit(&ugen_devt_list_mutex); 3836 3837 return (ugenp); 3838 } 3839 t = t->list_next; 3840 } 3841 mutex_exit(&ugen_devt_list_mutex); 3842 3843 return (ugenp); 3844 } 3845 3846 3847 static void 3848 ugen_free_devt(ugen_state_t *ugenp) 3849 { 3850 ugen_devt_list_entry_t *e, *next, *prev; 3851 major_t major = ddi_driver_major(ugenp->ug_dip); 3852 int instance = ddi_get_instance(ugenp->ug_dip); 3853 3854 mutex_enter(&ugen_devt_list_mutex); 3855 prev = &ugen_devt_list; 3856 for (e = prev->list_next; e != 0; e = next) { 3857 int i = (getminor(e->list_dev) & 3858 ugenp->ug_hdl->hdl_minor_node_instance_mask) >> 3859 ugenp->ug_hdl->hdl_minor_node_instance_shift; 3860 int m = getmajor(e->list_dev); 3861 3862 next = e->list_next; 3863 3864 if ((i == instance) && (m == major)) { 3865 prev->list_next = e->list_next; 3866 if (e->list_next) { 3867 e->list_next->list_prev = prev; 3868 } 3869 kmem_free(e, sizeof (ugen_devt_list_entry_t)); 3870 } else { 3871 prev = e; 3872 } 3873 } 3874 3875 bzero(ugen_devt_cache, sizeof (ugen_devt_cache)); 3876 ugen_devt_cache_index = 0; 3877 mutex_exit(&ugen_devt_list_mutex); 3878 } 3879