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