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