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