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