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