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