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