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;