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