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