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