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