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