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