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