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