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