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