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