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