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