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