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