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