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