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