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.
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.
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]
21 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
23 * Copyright (c) 2016 by Delphix. All rights reserved.
27 * Copyright 2016 Joyent, Inc.
31 * UGEN: USB Generic Driver support code
33 * This code provides entry points called by the ugen driver or other
34 * drivers that want to export a ugen interface
36 * The "Universal Generic Driver" (UGEN) for USB devices provides interfaces
37 * to talk to USB devices. This is very useful for Point of Sale sale
38 * devices and other simple devices like USB scanner, USB palm pilot.
39 * The UGEN provides a system call interface to USB devices enabling
40 * a USB device vendor to write an application for their
41 * device instead of writing a driver. This facilitates the vendor to write
42 * device management s/w quickly in userland.
44 * UGEN supports read/write/poll entry points. An application can be written
45 * using read/write/aioread/aiowrite/poll system calls to communicate
48 * XXX Theory of Operations
50 #include <sys/usb/usba/usbai_version.h>
51 #include <sys/usb/usba.h>
52 #include <sys/sysmacros.h>
53 #include <sys/strsun.h>
55 #include "sys/usb/clients/ugen/usb_ugen.h"
56 #include "sys/usb/usba/usba_ugen.h"
57 #include "sys/usb/usba/usba_ugend.h"
59 /* Debugging information */
60 uint_t ugen_errmask
= (uint_t
)UGEN_PRINT_ALL
;
61 uint_t ugen_errlevel
= USB_LOG_L4
;
62 uint_t ugen_instance_debug
= (uint_t
)-1;
64 /* default endpoint descriptor */
65 static usb_ep_descr_t ugen_default_ep_descr
=
66 {7, 5, 0, USB_EP_ATTR_CONTROL
, 8, 0};
69 int ugen_busy_loop
= 60; /* secs */
70 int ugen_ctrl_timeout
= 10;
71 int ugen_bulk_timeout
= 10;
72 int ugen_intr_timeout
= 10;
73 int ugen_enable_pm
= 0;
74 int ugen_isoc_buf_limit
= 1000; /* ms */
77 /* local function prototypes */
78 static int ugen_cleanup(ugen_state_t
*);
79 static int ugen_cpr_suspend(ugen_state_t
*);
80 static void ugen_cpr_resume(ugen_state_t
*);
82 static void ugen_restore_state(ugen_state_t
*);
83 static int ugen_check_open_flags(ugen_state_t
*, dev_t
, int);
84 static int ugen_strategy(struct buf
*);
85 static void ugen_minphys(struct buf
*);
87 static void ugen_pm_init(ugen_state_t
*);
88 static void ugen_pm_destroy(ugen_state_t
*);
89 static void ugen_pm_busy_component(ugen_state_t
*);
90 static void ugen_pm_idle_component(ugen_state_t
*);
92 /* endpoint xfer and status management */
93 static int ugen_epxs_init(ugen_state_t
*);
94 static void ugen_epxs_destroy(ugen_state_t
*);
95 static int ugen_epxs_data_init(ugen_state_t
*, usb_ep_data_t
*,
96 uchar_t
, uchar_t
, uchar_t
, uchar_t
);
97 static void ugen_epxs_data_destroy(ugen_state_t
*, ugen_ep_t
*);
98 static int ugen_epxs_minor_nodes_create(ugen_state_t
*,
99 usb_ep_descr_t
*, uchar_t
,
100 uchar_t
, uchar_t
, uchar_t
);
101 static int ugen_epxs_check_open_nodes(ugen_state_t
*);
103 static int ugen_epx_open(ugen_state_t
*, dev_t
, int);
104 static void ugen_epx_close(ugen_state_t
*, dev_t
, int);
105 static void ugen_epx_shutdown(ugen_state_t
*);
107 static int ugen_epx_open_pipe(ugen_state_t
*, ugen_ep_t
*, int);
108 static void ugen_epx_close_pipe(ugen_state_t
*, ugen_ep_t
*);
110 static int ugen_epx_req(ugen_state_t
*, struct buf
*);
111 static int ugen_epx_ctrl_req(ugen_state_t
*, ugen_ep_t
*,
112 struct buf
*, boolean_t
*);
113 static void ugen_epx_ctrl_req_cb(usb_pipe_handle_t
, usb_ctrl_req_t
*);
114 static int ugen_epx_bulk_req(ugen_state_t
*, ugen_ep_t
*,
115 struct buf
*, boolean_t
*);
116 static void ugen_epx_bulk_req_cb(usb_pipe_handle_t
, usb_bulk_req_t
*);
117 static int ugen_epx_intr_IN_req(ugen_state_t
*, ugen_ep_t
*,
118 struct buf
*, boolean_t
*);
119 static int ugen_epx_intr_IN_start_polling(ugen_state_t
*, ugen_ep_t
*);
120 static void ugen_epx_intr_IN_stop_polling(ugen_state_t
*, ugen_ep_t
*);
121 static void ugen_epx_intr_IN_req_cb(usb_pipe_handle_t
, usb_intr_req_t
*);
122 static int ugen_epx_intr_OUT_req(ugen_state_t
*, ugen_ep_t
*,
123 struct buf
*, boolean_t
*);
124 static void ugen_epx_intr_OUT_req_cb(usb_pipe_handle_t
, usb_intr_req_t
*);
125 static int ugen_epx_isoc_IN_req(ugen_state_t
*, ugen_ep_t
*,
126 struct buf
*, boolean_t
*);
127 static int ugen_epx_isoc_IN_start_polling(ugen_state_t
*, ugen_ep_t
*);
128 static void ugen_epx_isoc_IN_stop_polling(ugen_state_t
*, ugen_ep_t
*);
129 static void ugen_epx_isoc_IN_req_cb(usb_pipe_handle_t
, usb_isoc_req_t
*);
130 static int ugen_epx_isoc_OUT_req(ugen_state_t
*, ugen_ep_t
*,
131 struct buf
*, boolean_t
*);
132 static void ugen_epx_isoc_OUT_req_cb(usb_pipe_handle_t
, usb_isoc_req_t
*);
134 static int ugen_eps_open(ugen_state_t
*, dev_t
, int);
135 static void ugen_eps_close(ugen_state_t
*, dev_t
, int);
136 static int ugen_eps_req(ugen_state_t
*, struct buf
*);
137 static void ugen_update_ep_descr(ugen_state_t
*, ugen_ep_t
*);
139 /* device status management */
140 static int ugen_ds_init(ugen_state_t
*);
141 static void ugen_ds_destroy(ugen_state_t
*);
142 static int ugen_ds_open(ugen_state_t
*, dev_t
, int);
143 static void ugen_ds_close(ugen_state_t
*, dev_t
, int);
144 static int ugen_ds_req(ugen_state_t
*, struct buf
*);
145 static void ugen_ds_change(ugen_state_t
*);
146 static int ugen_ds_minor_nodes_create(ugen_state_t
*);
147 static void ugen_ds_poll_wakeup(ugen_state_t
*);
149 /* utility functions */
150 static int ugen_minor_index_create(ugen_state_t
*, ugen_minor_t
);
151 static ugen_minor_t
ugen_devt2minor(ugen_state_t
*, dev_t
);
152 static void ugen_minor_node_table_create(ugen_state_t
*);
153 static void ugen_minor_node_table_destroy(ugen_state_t
*);
154 static void ugen_minor_node_table_shrink(ugen_state_t
*);
155 static int ugen_cr2lcstat(int);
156 static void ugen_check_mask(uint_t
, uint_t
*, uint_t
*);
157 static int ugen_is_valid_minor_node(ugen_state_t
*, dev_t
);
159 static kmutex_t ugen_devt_list_mutex
;
160 static ugen_devt_list_entry_t ugen_devt_list
;
161 static ugen_devt_cache_entry_t ugen_devt_cache
[UGEN_DEVT_CACHE_SIZE
];
162 static uint_t ugen_devt_cache_index
;
163 static void ugen_store_devt(ugen_state_t
*, minor_t
);
164 static ugen_state_t
*ugen_devt2state(dev_t
);
165 static void ugen_free_devt(ugen_state_t
*);
168 * usb_ugen entry points
171 * allocate and initialize handle
174 usb_ugen_get_hdl(dev_info_t
*dip
, usb_ugen_info_t
*usb_ugen_info
)
176 usb_ugen_hdl_impl_t
*hdl
= kmem_zalloc(sizeof (*hdl
), KM_SLEEP
);
177 ugen_state_t
*ugenp
= kmem_zalloc(sizeof (ugen_state_t
),
179 uint_t len
, shift
, limit
;
182 hdl
->hdl_ugenp
= ugenp
;
184 /* masks may not overlap */
185 if (usb_ugen_info
->usb_ugen_minor_node_ugen_bits_mask
&
186 usb_ugen_info
->usb_ugen_minor_node_instance_mask
) {
187 usb_ugen_release_hdl((usb_ugen_hdl_t
)hdl
);
192 if ((rval
= usb_get_dev_data(dip
, &ugenp
->ug_dev_data
,
193 usb_owns_device(dip
) ? USB_PARSE_LVL_ALL
: USB_PARSE_LVL_IF
,
194 0)) != USB_SUCCESS
) {
195 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
196 "usb_ugen_attach: usb_get_dev_data failed, rval=%d", rval
);
201 /* Initialize state structure for this instance */
202 mutex_init(&ugenp
->ug_mutex
, NULL
, MUTEX_DRIVER
,
203 ugenp
->ug_dev_data
->dev_iblock_cookie
);
205 mutex_enter(&ugenp
->ug_mutex
);
207 ugenp
->ug_instance
= ddi_get_instance(dip
);
210 /* Allocate a log handle for debug/error messages */
211 if (strcmp(ddi_driver_name(dip
), "ugen") != 0) {
214 len
= strlen(ddi_driver_name(dip
)) + sizeof ("_ugen") + 1;
215 name
= kmem_alloc(len
, KM_SLEEP
);
216 (void) snprintf(name
, len
, "%s_ugen", ddi_driver_name(dip
));
218 ugenp
->ug_log_hdl
= usb_alloc_log_hdl(dip
, name
, &ugen_errlevel
,
219 &ugen_errmask
, &ugen_instance_debug
, 0);
220 hdl
->hdl_log_name
= name
;
221 hdl
->hdl_log_name_length
= len
;
223 ugenp
->ug_log_hdl
= usb_alloc_log_hdl(dip
, "ugen",
225 &ugen_errmask
, &ugen_instance_debug
, 0);
229 hdl
->hdl_flags
= usb_ugen_info
->usb_ugen_flags
;
231 ugen_check_mask(usb_ugen_info
->usb_ugen_minor_node_ugen_bits_mask
,
234 usb_ugen_release_hdl((usb_ugen_hdl_t
)hdl
);
235 mutex_exit(&ugenp
->ug_mutex
);
239 hdl
->hdl_minor_node_ugen_bits_mask
= usb_ugen_info
->
240 usb_ugen_minor_node_ugen_bits_mask
;
241 hdl
->hdl_minor_node_ugen_bits_shift
= shift
;
242 hdl
->hdl_minor_node_ugen_bits_limit
= limit
;
244 ugen_check_mask(usb_ugen_info
->usb_ugen_minor_node_instance_mask
,
247 usb_ugen_release_hdl((usb_ugen_hdl_t
)hdl
);
248 mutex_exit(&ugenp
->ug_mutex
);
253 hdl
->hdl_minor_node_instance_mask
= usb_ugen_info
->
254 usb_ugen_minor_node_instance_mask
;
255 hdl
->hdl_minor_node_instance_shift
= shift
;
256 hdl
->hdl_minor_node_instance_limit
= limit
;
258 USB_DPRINTF_L4(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
259 "usb_ugen_get_hdl: instance shift=%d instance limit=%d",
260 hdl
->hdl_minor_node_instance_shift
,
261 hdl
->hdl_minor_node_instance_limit
);
263 USB_DPRINTF_L4(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
264 "usb_ugen_get_hdl: bits shift=%d bits limit=%d",
265 hdl
->hdl_minor_node_ugen_bits_shift
,
266 hdl
->hdl_minor_node_ugen_bits_limit
);
268 mutex_exit(&ugenp
->ug_mutex
);
270 return ((usb_ugen_hdl_t
)hdl
);
275 * usb_ugen_release_hdl:
276 * deallocate a handle
279 usb_ugen_release_hdl(usb_ugen_hdl_t usb_ugen_hdl
)
281 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
282 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
284 if (usb_ugen_hdl_impl
) {
285 ugen_state_t
*ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
288 mutex_destroy(&ugenp
->ug_mutex
);
289 usb_free_log_hdl(ugenp
->ug_log_hdl
);
290 usb_free_dev_data(usb_ugen_hdl_impl
->hdl_dip
,
292 kmem_free(ugenp
, sizeof (*ugenp
));
294 if (usb_ugen_hdl_impl
->hdl_log_name
) {
295 kmem_free(usb_ugen_hdl_impl
->hdl_log_name
,
296 usb_ugen_hdl_impl
->hdl_log_name_length
);
298 kmem_free(usb_ugen_hdl_impl
, sizeof (*usb_ugen_hdl_impl
));
307 usb_ugen_attach(usb_ugen_hdl_t usb_ugen_hdl
, ddi_attach_cmd_t cmd
)
309 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
310 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
314 if (usb_ugen_hdl
== NULL
) {
316 return (USB_FAILURE
);
319 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
320 dip
= usb_ugen_hdl_impl
->hdl_dip
;
323 USB_DPRINTF_L4(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
324 "usb_ugen_attach: cmd=%d", cmd
);
331 ugen_cpr_resume(ugenp
);
333 return (USB_SUCCESS
);
335 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, NULL
,
336 "usb_ugen_attach: unknown command");
338 return (USB_FAILURE
);
341 mutex_enter(&ugenp
->ug_mutex
);
342 ugenp
->ug_ser_cookie
=
343 usb_init_serialization(dip
, USB_INIT_SER_CHECK_SAME_THREAD
);
344 ugenp
->ug_cleanup_flags
|= UGEN_INIT_LOCKS
;
346 /* Get maximum bulk transfer size supported by the HCD */
347 if (usb_pipe_get_max_bulk_transfer_size(dip
,
348 &ugenp
->ug_max_bulk_xfer_sz
) != USB_SUCCESS
) {
349 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
350 "usb_ugen_attach: Getting max bulk xfer sz failed");
351 mutex_exit(&ugenp
->ug_mutex
);
356 /* table for mapping 48 bit minor codes to 9 bit index (for ugen) */
357 ugen_minor_node_table_create(ugenp
);
359 /* prepare device status node handling */
360 if (ugen_ds_init(ugenp
) != USB_SUCCESS
) {
361 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
362 "usb_ugen_attach: preparing dev status failed");
363 mutex_exit(&ugenp
->ug_mutex
);
368 /* prepare all available xfer and status endpoints nodes */
369 if (ugen_epxs_init(ugenp
) != USB_SUCCESS
) {
370 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
371 "usb_ugen_attach: preparing endpoints failed");
372 mutex_exit(&ugenp
->ug_mutex
);
377 /* reduce table size if not all entries are used */
378 ugen_minor_node_table_shrink(ugenp
);
380 /* we are ready to go */
381 ugenp
->ug_dev_state
= USB_DEV_ONLINE
;
383 mutex_exit(&ugenp
->ug_mutex
);
386 if (ugenp
->ug_hdl
->hdl_flags
& USB_UGEN_ENABLE_PM
) {
391 * if ugen driver, kill all child nodes otherwise set cfg fails
394 if (usb_owns_device(dip
) &&
395 (usb_ugen_hdl_impl
->hdl_flags
& USB_UGEN_REMOVE_CHILDREN
)) {
398 /* save cfgidx so we can restore on detach */
399 mutex_enter(&ugenp
->ug_mutex
);
400 ugenp
->ug_initial_cfgidx
= usb_get_current_cfgidx(dip
);
401 mutex_exit(&ugenp
->ug_mutex
);
403 for (cdip
= ddi_get_child(dip
); cdip
; ) {
404 dev_info_t
*next
= ddi_get_next_sibling(cdip
);
405 (void) ddi_remove_child(cdip
, 0);
410 return (DDI_SUCCESS
);
413 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
415 (void) ugen_cleanup(ugenp
);
418 return (DDI_FAILURE
);
426 usb_ugen_detach(usb_ugen_hdl_t usb_ugen_hdl
, ddi_detach_cmd_t cmd
)
428 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
429 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
430 int rval
= USB_FAILURE
;
433 ugen_state_t
*ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
435 USB_DPRINTF_L4(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
436 "usb_ugen_detach cmd %d", cmd
);
440 rval
= ugen_cleanup(ugenp
);
444 rval
= ugen_cpr_suspend(ugenp
);
461 ugen_cleanup(ugen_state_t
*ugenp
)
463 dev_info_t
*dip
= ugenp
->ug_dip
;
465 USB_DPRINTF_L4(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
, "ugen_cleanup");
467 if (ugenp
->ug_cleanup_flags
& UGEN_INIT_LOCKS
) {
469 /* shutdown all endpoints */
470 ugen_epx_shutdown(ugenp
);
473 * At this point, no new activity can be initiated.
474 * The driver has disabled hotplug callbacks.
475 * The Solaris framework has disabled
476 * new opens on a device being detached, and does not
477 * allow detaching an open device. PM should power
478 * down while we are detaching
480 * The following ensures that any other driver
481 * activity must have drained (paranoia)
483 (void) usb_serialize_access(ugenp
->ug_ser_cookie
,
485 usb_release_access(ugenp
->ug_ser_cookie
);
487 mutex_enter(&ugenp
->ug_mutex
);
488 ASSERT(ugenp
->ug_open_count
== 0);
489 ASSERT(ugenp
->ug_pending_cmds
== 0);
491 /* dismantle in reverse order */
492 ugen_pm_destroy(ugenp
);
493 ugen_epxs_destroy(ugenp
);
494 ugen_ds_destroy(ugenp
);
495 ugen_minor_node_table_destroy(ugenp
);
498 /* restore to initial configuration */
499 if (usb_owns_device(dip
) &&
500 (ugenp
->ug_dev_state
!= USB_DEV_DISCONNECTED
)) {
501 int idx
= ugenp
->ug_initial_cfgidx
;
502 mutex_exit(&ugenp
->ug_mutex
);
503 (void) usb_set_cfg(dip
, idx
,
504 USB_FLAGS_SLEEP
, NULL
, NULL
);
506 mutex_exit(&ugenp
->ug_mutex
);
509 usb_fini_serialization(ugenp
->ug_ser_cookie
);
512 ddi_prop_remove_all(dip
);
513 ddi_remove_minor_node(dip
, NULL
);
515 ugen_free_devt(ugenp
);
517 return (USB_SUCCESS
);
525 ugen_cpr_suspend(ugen_state_t
*ugenp
)
527 int rval
= USB_FAILURE
;
531 USB_DPRINTF_L4(UGEN_PRINT_CPR
, ugenp
->ug_log_hdl
,
532 "ugen_cpr_suspend:");
534 mutex_enter(&ugenp
->ug_mutex
);
535 switch (ugenp
->ug_dev_state
) {
537 case USB_DEV_DISCONNECTED
:
538 USB_DPRINTF_L4(UGEN_PRINT_CPR
, ugenp
->ug_log_hdl
,
539 "ugen_cpr_suspend:");
541 prev_state
= ugenp
->ug_dev_state
;
542 ugenp
->ug_dev_state
= USB_DEV_SUSPENDED
;
544 if (ugenp
->ug_open_count
) {
545 /* drain outstanding cmds */
546 for (i
= 0; i
< ugen_busy_loop
; i
++) {
547 if (ugenp
->ug_pending_cmds
== 0) {
551 mutex_exit(&ugenp
->ug_mutex
);
552 delay(drv_usectohz(100000));
553 mutex_enter(&ugenp
->ug_mutex
);
556 /* if still outstanding cmds, fail suspend */
557 if (ugenp
->ug_pending_cmds
) {
558 ugenp
->ug_dev_state
= prev_state
;
560 USB_DPRINTF_L2(UGEN_PRINT_CPR
,
562 "ugen_cpr_suspend: pending %d",
563 ugenp
->ug_pending_cmds
);
569 mutex_exit(&ugenp
->ug_mutex
);
570 (void) usb_serialize_access(ugenp
->ug_ser_cookie
,
572 /* close all pipes */
573 ugen_epx_shutdown(ugenp
);
575 usb_release_access(ugenp
->ug_ser_cookie
);
577 mutex_enter(&ugenp
->ug_mutex
);
580 /* wakeup devstat reads and polls */
581 ugen_ds_change(ugenp
);
582 ugen_ds_poll_wakeup(ugenp
);
586 case USB_DEV_SUSPENDED
:
587 case USB_UGEN_DEV_UNAVAILABLE_RESUME
:
588 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT
:
593 mutex_exit(&ugenp
->ug_mutex
);
602 ugen_cpr_resume(ugen_state_t
*ugenp
)
604 USB_DPRINTF_L4(UGEN_PRINT_CPR
, ugenp
->ug_log_hdl
,
607 ugen_restore_state(ugenp
);
611 * usb_ugen_disconnect_ev_cb:
614 usb_ugen_disconnect_ev_cb(usb_ugen_hdl_t usb_ugen_hdl
)
616 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
617 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
620 if (usb_ugen_hdl_impl
== NULL
) {
622 return (USB_FAILURE
);
625 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
627 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG
, ugenp
->ug_log_hdl
,
628 "usb_ugen_disconnect_ev_cb:");
630 /* get exclusive access */
631 (void) usb_serialize_access(ugenp
->ug_ser_cookie
, USB_WAIT
, 0);
633 mutex_enter(&ugenp
->ug_mutex
);
634 ugenp
->ug_dev_state
= USB_DEV_DISCONNECTED
;
635 if (ugenp
->ug_open_count
) {
636 mutex_exit(&ugenp
->ug_mutex
);
638 /* close all pipes */
639 (void) ugen_epx_shutdown(ugenp
);
641 mutex_enter(&ugenp
->ug_mutex
);
645 /* wakeup devstat reads and polls */
646 ugen_ds_change(ugenp
);
647 ugen_ds_poll_wakeup(ugenp
);
649 mutex_exit(&ugenp
->ug_mutex
);
650 usb_release_access(ugenp
->ug_ser_cookie
);
652 return (USB_SUCCESS
);
657 * usb_ugen_reconnect_ev_cb:
660 usb_ugen_reconnect_ev_cb(usb_ugen_hdl_t usb_ugen_hdl
)
662 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
663 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
664 ugen_state_t
*ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
666 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG
, ugenp
->ug_log_hdl
,
667 "usb_ugen_reconnect_ev_cb:");
669 ugen_restore_state(ugenp
);
671 return (USB_SUCCESS
);
676 * ugen_restore_state:
677 * Check for same device; if a different device is attached, set
678 * the device status to disconnected.
679 * If we were open, then set to UNAVAILABLE until all endpoints have
683 ugen_restore_state(ugen_state_t
*ugenp
)
685 dev_info_t
*dip
= ugenp
->ug_dip
;
687 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG
, ugenp
->ug_log_hdl
,
688 "ugen_restore_state");
690 /* first raise power */
691 if (ugenp
->ug_hdl
->hdl_flags
& USB_UGEN_ENABLE_PM
) {
692 ugen_pm_busy_component(ugenp
);
693 (void) pm_raise_power(dip
, 0, USB_DEV_OS_FULL_PWR
);
696 /* Check if we are talking to the same device */
697 if (usb_check_same_device(dip
, ugenp
->ug_log_hdl
,
698 USB_LOG_L0
, UGEN_PRINT_HOTPLUG
, USB_CHK_ALL
, NULL
) ==
700 mutex_enter(&ugenp
->ug_mutex
);
701 ugenp
->ug_dev_state
= USB_DEV_DISCONNECTED
;
703 /* wakeup devstat reads and polls */
704 ugen_ds_change(ugenp
);
705 ugen_ds_poll_wakeup(ugenp
);
707 mutex_exit(&ugenp
->ug_mutex
);
709 if (ugenp
->ug_hdl
->hdl_flags
& USB_UGEN_ENABLE_PM
) {
710 ugen_pm_idle_component(ugenp
);
717 * get exclusive access, we don't want to change state in the
718 * middle of some other actions
720 (void) usb_serialize_access(ugenp
->ug_ser_cookie
, USB_WAIT
, 0);
722 mutex_enter(&ugenp
->ug_mutex
);
723 switch (ugenp
->ug_dev_state
) {
724 case USB_DEV_DISCONNECTED
:
725 ugenp
->ug_dev_state
= (ugenp
->ug_open_count
== 0) ?
726 USB_DEV_ONLINE
: USB_UGEN_DEV_UNAVAILABLE_RECONNECT
;
729 case USB_DEV_SUSPENDED
:
730 ugenp
->ug_dev_state
= (ugenp
->ug_open_count
== 0) ?
731 USB_DEV_ONLINE
: USB_UGEN_DEV_UNAVAILABLE_RESUME
;
735 USB_DPRINTF_L4(UGEN_PRINT_HOTPLUG
, ugenp
->ug_log_hdl
,
736 "ugen_restore_state: state=%d, opencount=%d",
737 ugenp
->ug_dev_state
, ugenp
->ug_open_count
);
739 /* wakeup devstat reads and polls */
740 ugen_ds_change(ugenp
);
741 ugen_ds_poll_wakeup(ugenp
);
743 mutex_exit(&ugenp
->ug_mutex
);
744 usb_release_access(ugenp
->ug_ser_cookie
);
746 if (ugenp
->ug_hdl
->hdl_flags
& USB_UGEN_ENABLE_PM
) {
747 ugen_pm_idle_component(ugenp
);
757 usb_ugen_open(usb_ugen_hdl_t usb_ugen_hdl
, dev_t
*devp
, int flag
, int sflag
,
760 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
761 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
766 if (usb_ugen_hdl
== NULL
) {
771 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
773 if (ugen_is_valid_minor_node(ugenp
, *devp
) != USB_SUCCESS
) {
778 minor_node_type
= UGEN_MINOR_TYPE(ugenp
, *devp
);
780 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
781 "usb_ugen_open: minor=%u", getminor(*devp
));
782 USB_DPRINTF_L3(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
783 "cfgval=%" PRIu64
" cfgidx=%" PRIu64
" if=%" PRIu64
784 " alt=%" PRIu64
" epidx=%" PRIu64
" type=0x%" PRIx64
,
785 UGEN_MINOR_CFGVAL(ugenp
, *devp
), UGEN_MINOR_CFGIDX(ugenp
, *devp
),
786 UGEN_MINOR_IF(ugenp
, *devp
), UGEN_MINOR_ALT(ugenp
, *devp
),
787 UGEN_MINOR_EPIDX(ugenp
, *devp
), UGEN_MINOR_TYPE(ugenp
, *devp
));
789 /* first check for legal open flags */
790 if ((rval
= ugen_check_open_flags(ugenp
, *devp
, flag
)) != 0) {
791 USB_DPRINTF_L2(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
792 "usb_ugen_open: check failed, rval=%d", rval
);
797 /* exclude other threads including other opens */
798 if (usb_serialize_access(ugenp
->ug_ser_cookie
,
799 USB_WAIT_SIG
, 0) <= 0) {
800 USB_DPRINTF_L2(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
801 "usb_ugen_open: interrupted");
806 mutex_enter(&ugenp
->ug_mutex
);
808 /* always allow open of dev stat node */
809 if (minor_node_type
!= UGEN_MINOR_DEV_STAT_NODE
) {
811 /* if we are not online or powered down, fail open */
812 switch (ugenp
->ug_dev_state
) {
816 case USB_DEV_DISCONNECTED
:
818 mutex_exit(&ugenp
->ug_mutex
);
821 case USB_DEV_SUSPENDED
:
822 case USB_UGEN_DEV_UNAVAILABLE_RESUME
:
823 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT
:
826 mutex_exit(&ugenp
->ug_mutex
);
831 mutex_exit(&ugenp
->ug_mutex
);
833 /* open node depending on type */
834 switch (minor_node_type
) {
835 case UGEN_MINOR_EP_XFER_NODE
:
836 if (ugenp
->ug_hdl
->hdl_flags
& USB_UGEN_ENABLE_PM
) {
837 ugen_pm_busy_component(ugenp
);
838 (void) pm_raise_power(ugenp
->ug_dip
, 0,
839 USB_DEV_OS_FULL_PWR
);
842 rval
= ugen_epx_open(ugenp
, *devp
, flag
);
844 mutex_enter(&ugenp
->ug_mutex
);
845 ugenp
->ug_open_count
++;
846 mutex_exit(&ugenp
->ug_mutex
);
848 if (ugenp
->ug_hdl
->hdl_flags
&
849 USB_UGEN_ENABLE_PM
) {
850 ugen_pm_idle_component(ugenp
);
855 case UGEN_MINOR_EP_STAT_NODE
:
856 rval
= ugen_eps_open(ugenp
, *devp
, flag
);
858 mutex_enter(&ugenp
->ug_mutex
);
859 ugenp
->ug_open_count
++;
860 mutex_exit(&ugenp
->ug_mutex
);
864 case UGEN_MINOR_DEV_STAT_NODE
:
865 rval
= ugen_ds_open(ugenp
, *devp
, flag
);
874 mutex_enter(&ugenp
->ug_mutex
);
876 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
877 "usb_ugen_open: minor=0x%x rval=%d state=%d cnt=%d",
878 getminor(*devp
), rval
, ugenp
->ug_dev_state
,
879 ugenp
->ug_open_count
);
881 mutex_exit(&ugenp
->ug_mutex
);
883 usb_release_access(ugenp
->ug_ser_cookie
);
894 usb_ugen_close(usb_ugen_hdl_t usb_ugen_hdl
, dev_t dev
, int flag
, int otype
,
897 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
898 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
902 if (usb_ugen_hdl
== NULL
) {
907 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
908 if (ugen_is_valid_minor_node(ugenp
, dev
) != USB_SUCCESS
) {
913 minor_node_type
= UGEN_MINOR_TYPE(ugenp
, dev
);
915 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
916 "usb_ugen_close: minor=0x%x", getminor(dev
));
918 /* exclude other threads, including other opens */
919 if (usb_serialize_access(ugenp
->ug_ser_cookie
,
920 USB_WAIT_SIG
, 0) <= 0) {
921 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
922 "usb_ugen_close: interrupted");
927 /* close node depending on type */
928 switch (minor_node_type
) {
929 case UGEN_MINOR_EP_XFER_NODE
:
930 ugen_epx_close(ugenp
, dev
, flag
);
931 if (ugenp
->ug_hdl
->hdl_flags
& USB_UGEN_ENABLE_PM
) {
932 ugen_pm_idle_component(ugenp
);
936 case UGEN_MINOR_EP_STAT_NODE
:
937 ugen_eps_close(ugenp
, dev
, flag
);
940 case UGEN_MINOR_DEV_STAT_NODE
:
941 ugen_ds_close(ugenp
, dev
, flag
);
945 usb_release_access(ugenp
->ug_ser_cookie
);
950 mutex_enter(&ugenp
->ug_mutex
);
951 if (minor_node_type
!= UGEN_MINOR_DEV_STAT_NODE
) {
952 ASSERT(ugenp
->ug_open_count
> 0);
953 if ((--ugenp
->ug_open_count
== 0) &&
954 ((ugenp
->ug_dev_state
== USB_UGEN_DEV_UNAVAILABLE_RESUME
) ||
955 (ugenp
->ug_dev_state
==
956 USB_UGEN_DEV_UNAVAILABLE_RECONNECT
))) {
957 ugenp
->ug_dev_state
= USB_DEV_ONLINE
;
959 /* wakeup devstat reads and polls */
960 ugen_ds_change(ugenp
);
961 ugen_ds_poll_wakeup(ugenp
);
965 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
966 "usb_ugen_close: minor=0x%x state=%d cnt=%d",
967 getminor(dev
), ugenp
->ug_dev_state
, ugenp
->ug_open_count
);
969 if (ugenp
->ug_open_count
== 0) {
970 ASSERT(ugen_epxs_check_open_nodes(ugenp
) == USB_FAILURE
);
973 mutex_exit(&ugenp
->ug_mutex
);
975 usb_release_access(ugenp
->ug_ser_cookie
);
982 * usb_ugen_read/write()
986 usb_ugen_read(usb_ugen_hdl_t usb_ugen_hdl
, dev_t dev
, struct uio
*uiop
,
990 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
991 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
993 if (usb_ugen_hdl
== NULL
) {
997 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
999 if (ugen_is_valid_minor_node(ugenp
, dev
) != USB_SUCCESS
) {
1004 return (physio(ugen_strategy
,
1005 NULL
, dev
, B_READ
, ugen_minphys
, uiop
));
1011 usb_ugen_write(usb_ugen_hdl_t usb_ugen_hdl
, dev_t dev
, struct uio
*uiop
,
1014 ugen_state_t
*ugenp
;
1015 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
1016 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
1018 if (usb_ugen_hdl
== NULL
) {
1022 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
1024 if (ugen_is_valid_minor_node(ugenp
, dev
) != USB_SUCCESS
) {
1029 return (physio(ugen_strategy
,
1030 NULL
, dev
, B_WRITE
, ugen_minphys
, uiop
));
1038 usb_ugen_poll(usb_ugen_hdl_t usb_ugen_hdl
, dev_t dev
, short events
,
1039 int anyyet
, short *reventsp
, struct pollhead
**phpp
)
1041 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
1042 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
1043 ugen_state_t
*ugenp
;
1044 int minor_node_type
;
1048 if (usb_ugen_hdl
== NULL
) {
1053 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
1054 if (ugen_is_valid_minor_node(ugenp
, dev
) != USB_SUCCESS
) {
1059 minor_node_type
= UGEN_MINOR_TYPE(ugenp
, dev
);
1060 ep_index
= UGEN_MINOR_EPIDX(ugenp
, dev
);
1061 epp
= &ugenp
->ug_ep
[ep_index
];
1063 mutex_enter(&ugenp
->ug_mutex
);
1065 USB_DPRINTF_L4(UGEN_PRINT_POLL
, ugenp
->ug_log_hdl
,
1067 "dev=0x%lx events=0x%x anyyet=0x%x rev=0x%p type=%d "
1068 "devstat=0x%x devstate=0x%x",
1069 dev
, events
, anyyet
, (void *)reventsp
, minor_node_type
,
1070 ugenp
->ug_ds
.dev_stat
, ugenp
->ug_ds
.dev_state
);
1074 if (ugenp
->ug_dev_state
== USB_DEV_ONLINE
) {
1075 switch (minor_node_type
) {
1076 case UGEN_MINOR_EP_XFER_NODE
:
1077 /* if interrupt IN ep and there is data, set POLLIN */
1078 if ((UGEN_XFER_TYPE(epp
) == USB_EP_ATTR_INTR
) &&
1079 (UGEN_XFER_DIR(epp
) & USB_EP_DIR_IN
)) {
1082 * if we are not polling, force another
1083 * read to kick off polling
1085 mutex_enter(&epp
->ep_mutex
);
1086 if ((epp
->ep_data
) ||
1088 UGEN_EP_STATE_INTR_IN_POLLING_ON
) == 0)) {
1089 *reventsp
|= POLLIN
;
1092 if ((!*reventsp
&& !anyyet
) ||
1093 (events
& POLLET
)) {
1094 *phpp
= &epp
->ep_pollhead
;
1096 UGEN_EP_STATE_INTR_IN_POLL_PENDING
;
1098 mutex_exit(&epp
->ep_mutex
);
1100 } else if ((UGEN_XFER_TYPE(epp
) == USB_EP_ATTR_ISOCH
) &&
1101 (UGEN_XFER_DIR(epp
) & USB_EP_DIR_IN
)) {
1104 * if we are not polling, force another
1105 * read to kick off polling
1107 mutex_enter(&epp
->ep_mutex
);
1108 if ((epp
->ep_data
) ||
1110 UGEN_EP_STATE_ISOC_IN_POLLING_ON
) == 0)) {
1111 *reventsp
|= POLLIN
;
1114 if ((!*reventsp
&& !anyyet
) ||
1115 (events
& POLLET
)) {
1116 *phpp
= &epp
->ep_pollhead
;
1118 UGEN_EP_STATE_ISOC_IN_POLL_PENDING
;
1120 mutex_exit(&epp
->ep_mutex
);
1123 /* no poll on other ep nodes */
1124 *reventsp
|= POLLERR
;
1128 case UGEN_MINOR_DEV_STAT_NODE
:
1129 if (ugenp
->ug_ds
.dev_stat
& UGEN_DEV_STATUS_CHANGED
)
1130 *reventsp
|= POLLIN
;
1132 if ((!*reventsp
&& !anyyet
) || (events
& POLLET
)) {
1133 *phpp
= &ugenp
->ug_ds
.dev_pollhead
;
1134 ugenp
->ug_ds
.dev_stat
|=
1135 UGEN_DEV_STATUS_POLL_PENDING
;
1139 case UGEN_MINOR_EP_STAT_NODE
:
1141 *reventsp
|= POLLERR
;
1146 if (ugenp
->ug_ds
.dev_stat
& UGEN_DEV_STATUS_CHANGED
)
1147 *reventsp
|= POLLHUP
|POLLIN
;
1149 if ((!*reventsp
&& !anyyet
) || (events
& POLLET
)) {
1150 *phpp
= &ugenp
->ug_ds
.dev_pollhead
;
1151 ugenp
->ug_ds
.dev_stat
|=
1152 UGEN_DEV_STATUS_POLL_PENDING
;
1156 mutex_exit(&ugenp
->ug_mutex
);
1158 USB_DPRINTF_L4(UGEN_PRINT_POLL
, ugenp
->ug_log_hdl
,
1159 "usb_ugen_poll end: reventsp=0x%x", *reventsp
);
1169 ugen_strategy(struct buf
*bp
)
1171 dev_t dev
= bp
->b_edev
;
1173 ugen_state_t
*ugenp
= ugen_devt2state(dev
);
1174 int minor_node_type
= UGEN_MINOR_TYPE(ugenp
, dev
);
1176 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1177 "ugen_strategy: bp=0x%p minor=0x%x", (void *)bp
, getminor(dev
));
1179 if (ugen_is_valid_minor_node(ugenp
, dev
) != USB_SUCCESS
) {
1184 mutex_enter(&ugenp
->ug_mutex
);
1185 ugenp
->ug_pending_cmds
++;
1186 mutex_exit(&ugenp
->ug_mutex
);
1190 switch (minor_node_type
) {
1191 case UGEN_MINOR_EP_XFER_NODE
:
1192 rval
= ugen_epx_req(ugenp
, bp
);
1195 case UGEN_MINOR_EP_STAT_NODE
:
1196 rval
= ugen_eps_req(ugenp
, bp
);
1199 case UGEN_MINOR_DEV_STAT_NODE
:
1200 rval
= ugen_ds_req(ugenp
, bp
);
1209 mutex_enter(&ugenp
->ug_mutex
);
1210 ugenp
->ug_pending_cmds
--;
1212 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1214 "bp=0x%p cnt=%lu resid=%lu err=%d minor=0x%x rval=%d #cmds=%d",
1215 (void *)bp
, bp
->b_bcount
, bp
->b_resid
, geterror(bp
),
1216 getminor(dev
), rval
, ugenp
->ug_pending_cmds
);
1218 mutex_exit(&ugenp
->ug_mutex
);
1221 if (geterror(bp
) == 0) {
1236 ugen_minphys(struct buf
*bp
)
1238 dev_t dev
= bp
->b_edev
;
1239 ugen_state_t
*ugenp
= ugen_devt2state(dev
);
1240 int minor_node_type
= UGEN_MINOR_TYPE(ugenp
, dev
);
1241 uint_t ep_index
= UGEN_MINOR_EPIDX(ugenp
, dev
);
1242 ugen_ep_t
*epp
= &ugenp
->ug_ep
[ep_index
];
1244 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1245 "ugen_phys: bp=0x%p dev=0x%lx index=%d type=0x%x",
1246 (void *)bp
, dev
, ep_index
, minor_node_type
);
1248 switch (minor_node_type
) {
1249 case UGEN_MINOR_EP_XFER_NODE
:
1250 switch (UGEN_XFER_TYPE(epp
)) {
1251 case USB_EP_ATTR_BULK
:
1252 if (bp
->b_bcount
> ugenp
->ug_max_bulk_xfer_sz
) {
1253 bp
->b_bcount
= ugenp
->ug_max_bulk_xfer_sz
;
1257 case USB_EP_ATTR_INTR
:
1258 case USB_EP_ATTR_CONTROL
:
1259 case USB_EP_ATTR_ISOCH
:
1265 case UGEN_MINOR_EP_STAT_NODE
:
1266 case UGEN_MINOR_DEV_STAT_NODE
:
1274 * Get bmAttributes and bAddress of the endpoint which is going to
1278 ugen_get_ep_descr(ugen_state_t
*ugenp
, dev_t dev
, uint8_t *bmAttr
,
1281 uint_t alt
= UGEN_MINOR_ALT(ugenp
, dev
);
1282 uint_t ifc
= UGEN_MINOR_IF(ugenp
, dev
);
1283 uint_t cfgidx
= UGEN_MINOR_CFGIDX(ugenp
, dev
);
1284 usb_cfg_data_t
*dev_cfg
;
1285 usb_if_data_t
*if_data
;
1286 usb_alt_if_data_t
*alt_if_data
;
1287 usb_ep_data_t
*ep_data
;
1289 int epidx
= UGEN_MINOR_EPIDX(ugenp
, dev
);
1291 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1292 "cfg=%d, if=%d, alt=%d, ep=0x%x", cfgidx
, ifc
,
1295 dev_cfg
= &ugenp
->ug_dev_data
->dev_cfg
[cfgidx
];
1296 if_data
= &dev_cfg
->cfg_if
[ifc
];
1297 alt_if_data
= &if_data
->if_alt
[alt
];
1298 for (ep
= 0; ep
< alt_if_data
->altif_n_ep
; ep
++) {
1299 ep_data
= &alt_if_data
->altif_ep
[ep
];
1301 if (usb_get_ep_index(ep_data
->ep_descr
.
1302 bEndpointAddress
) == epidx
) {
1304 *bmAttr
= ep_data
->ep_descr
.bmAttributes
;
1305 *bAddr
= ep_data
->ep_descr
.bEndpointAddress
;
1307 return (USB_SUCCESS
);
1311 return (USB_FAILURE
);
1315 * check whether flag is appropriate for node type
1318 ugen_check_open_flags(ugen_state_t
*ugenp
, dev_t dev
, int flag
)
1321 int minor_node_type
= UGEN_MINOR_TYPE(ugenp
, dev
);
1323 uint8_t bmAttribute
;
1326 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1327 "ugen_check_open_flags: "
1328 "dev=0x%lx, type=0x%x flag=0x%x idx=%" PRIu64
,
1329 dev
, minor_node_type
, flag
, UGEN_MINOR_EPIDX(ugenp
, dev
));
1331 switch (minor_node_type
) {
1332 case UGEN_MINOR_EP_XFER_NODE
:
1333 epp
= &ugenp
->ug_ep
[UGEN_MINOR_EPIDX(ugenp
, dev
)];
1336 * Endpoints in two altsetting happen to have the same
1337 * bEndpointAddress, but they are different type, e.g,
1338 * one is BULK and the other is ISOC. They use the same
1339 * slot of ug_ep array. It's OK after switch_alt, because
1340 * after alt switch, ep info is updated to the new endpoint.
1341 * But it's not right here to use the other EP's info for
1344 if (UGEN_MINOR_EPIDX(ugenp
, dev
) != 0) {
1345 if ((rval
= ugen_get_ep_descr(ugenp
, dev
, &bmAttribute
,
1346 &bAddress
)) != USB_SUCCESS
) {
1347 USB_DPRINTF_L2(UGEN_PRINT_XFER
,
1348 ugenp
->ug_log_hdl
, "ugen_get_descr: fail");
1353 bmAttribute
= ugen_default_ep_descr
.bmAttributes
;
1354 bAddress
= ugen_default_ep_descr
.bEndpointAddress
;
1357 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1358 "ugen_check_open_flags: epp = %p,"
1359 "epp type = %d, bmAttr =0x%x, bAddr = 0x%02x", (void *)epp
,
1360 UGEN_XFER_TYPE(epp
), bmAttribute
, bAddress
);
1362 switch (bmAttribute
& USB_EP_ATTR_MASK
) {
1363 case USB_EP_ATTR_CONTROL
:
1364 /* read and write must be set, ndelay not allowed */
1365 if (((flag
& (FREAD
| FWRITE
)) != (FREAD
| FWRITE
)) ||
1366 (flag
& (FNDELAY
| FNONBLOCK
))) {
1371 case USB_EP_ATTR_ISOCH
:
1372 /* read and write must be set */
1373 if ((flag
& (FREAD
| FWRITE
)) != (FREAD
| FWRITE
)) {
1378 case USB_EP_ATTR_BULK
:
1379 /* ndelay not allowed */
1380 if (flag
& (FNDELAY
| FNONBLOCK
)) {
1386 case USB_EP_ATTR_INTR
:
1387 /* check flag versus direction */
1388 if ((flag
& FWRITE
) && (bAddress
& USB_EP_DIR_IN
)) {
1391 if ((flag
& FREAD
) &&
1392 ((bAddress
& USB_EP_DIR_IN
) == 0)) {
1403 case UGEN_MINOR_DEV_STAT_NODE
:
1404 /* only reads are supported */
1405 if (flag
& FWRITE
) {
1410 case UGEN_MINOR_EP_STAT_NODE
:
1424 * endpoint management
1426 * create/initialize all endpoint xfer/stat structures
1429 ugen_epxs_init(ugen_state_t
*ugenp
)
1431 usb_cfg_data_t
*dev_cfg
= ugenp
->ug_dev_data
->dev_cfg
;
1432 uchar_t cfgidx
, cfgval
, iface
, alt
, ep
;
1433 usb_if_data_t
*if_data
;
1434 usb_alt_if_data_t
*alt_if_data
;
1435 usb_ep_data_t
*ep_data
;
1437 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1440 /* initialize each ep's mutex first */
1441 for (ep
= 0; ep
< UGEN_N_ENDPOINTS
; ep
++) {
1442 mutex_init(&ugenp
->ug_ep
[ep
].ep_mutex
, NULL
, MUTEX_DRIVER
,
1443 ugenp
->ug_dev_data
->dev_iblock_cookie
);
1446 /* init default ep as it does not have a descriptor */
1447 if (ugen_epxs_data_init(ugenp
, NULL
, 0, 0,
1448 ugenp
->ug_dev_data
->dev_curr_if
, 0) != USB_SUCCESS
) {
1449 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
1450 "creating default endpoint failed");
1452 return (USB_FAILURE
);
1456 * walk all endpoints of all alternates of all interfaces of
1459 for (cfgidx
= 0; cfgidx
< ugenp
->ug_dev_data
->dev_n_cfg
; cfgidx
++) {
1460 dev_cfg
= &ugenp
->ug_dev_data
->dev_cfg
[cfgidx
];
1461 cfgval
= dev_cfg
->cfg_descr
.bConfigurationValue
;
1462 for (iface
= 0; iface
< dev_cfg
->cfg_n_if
; iface
++) {
1463 if_data
= &dev_cfg
->cfg_if
[iface
];
1464 for (alt
= 0; alt
< if_data
->if_n_alt
; alt
++) {
1465 alt_if_data
= &if_data
->if_alt
[alt
];
1466 for (ep
= 0; ep
< alt_if_data
->altif_n_ep
;
1468 ep_data
= &alt_if_data
->altif_ep
[ep
];
1469 if (ugen_epxs_data_init(ugenp
, ep_data
,
1470 cfgval
, cfgidx
, iface
, alt
) !=
1473 return (USB_FAILURE
);
1480 return (USB_SUCCESS
);
1485 * initialize one endpoint structure
1488 ugen_epxs_data_init(ugen_state_t
*ugenp
, usb_ep_data_t
*ep_data
,
1489 uchar_t cfgval
, uchar_t cfgidx
, uchar_t iface
, uchar_t alt
)
1493 usb_ep_descr_t
*ep_descr
;
1495 /* is this the default endpoint */
1496 ep_index
= (ep_data
== NULL
) ? 0 :
1497 usb_get_ep_index(ep_data
->ep_descr
.bEndpointAddress
);
1498 epp
= &ugenp
->ug_ep
[ep_index
];
1500 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1501 "ugen_epxs_data_init: "
1502 "cfgval=%d cfgidx=%d iface=%d alt=%d ep_index=%d",
1503 cfgval
, cfgidx
, iface
, alt
, ep_index
);
1505 ep_descr
= (ep_data
== NULL
) ? &ugen_default_ep_descr
:
1508 mutex_init(&epp
->ep_mutex
, NULL
, MUTEX_DRIVER
,
1509 ugenp
->ug_dev_data
->dev_iblock_cookie
);
1511 mutex_enter(&epp
->ep_mutex
);
1513 /* initialize if not yet init'ed */
1514 if (epp
->ep_state
== UGEN_EP_STATE_NONE
) {
1515 epp
->ep_descr
= *ep_descr
;
1516 epp
->ep_cfgidx
= cfgidx
;
1519 epp
->ep_state
= UGEN_EP_STATE_ACTIVE
;
1520 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
1521 epp
->ep_pipe_policy
.pp_max_async_reqs
= 1;
1523 if (ep_data
== NULL
) {
1524 bzero(&epp
->ep_xdescr
, sizeof (usb_ep_xdescr_t
));
1525 epp
->ep_xdescr
.uex_version
=
1526 USB_EP_XDESCR_CURRENT_VERSION
;
1527 epp
->ep_xdescr
.uex_ep
= *ep_descr
;
1530 * The only way this could fail is we have a bad
1531 * version, which shouldn't be possible inside of the
1532 * usba module itself.
1534 (void) usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION
,
1535 ugenp
->ug_dip
, ep_data
, &epp
->ep_xdescr
);
1538 cv_init(&epp
->ep_wait_cv
, NULL
, CV_DRIVER
, NULL
);
1539 epp
->ep_ser_cookie
= usb_init_serialization(
1543 mutex_exit(&epp
->ep_mutex
);
1545 /* create minor nodes for all alts */
1547 return (ugen_epxs_minor_nodes_create(ugenp
, ep_descr
,
1548 cfgval
, cfgidx
, iface
, alt
));
1553 * undo all endpoint initializations
1556 ugen_epxs_destroy(ugen_state_t
*ugenp
)
1560 for (i
= 0; i
< UGEN_N_ENDPOINTS
; i
++) {
1561 ugen_epxs_data_destroy(ugenp
, &ugenp
->ug_ep
[i
]);
1567 ugen_epxs_data_destroy(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
1570 ASSERT(epp
->ep_ph
== NULL
);
1571 mutex_enter(&epp
->ep_mutex
);
1572 if (epp
->ep_state
!= UGEN_EP_STATE_NONE
) {
1573 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1574 "ugen_epxs_destroy: addr=0x%x",
1575 UGEN_XFER_ADDR(epp
));
1576 cv_destroy(&epp
->ep_wait_cv
);
1578 mutex_exit(&epp
->ep_mutex
);
1580 mutex_destroy(&epp
->ep_mutex
);
1581 usb_fini_serialization(epp
->ep_ser_cookie
);
1587 * create endpoint status and xfer minor nodes
1589 * The actual minor node needs more than 18 bits. We create a table
1590 * and store the full minor node in this table and use the
1591 * index in the table as minor node. This allows 256 minor nodes
1592 * and 1024 instances
1595 ugen_epxs_minor_nodes_create(ugen_state_t
*ugenp
, usb_ep_descr_t
*ep_descr
,
1596 uchar_t cfgval
, uchar_t cfgidx
, uchar_t iface
, uchar_t alt
)
1598 char node_name
[32], *type
;
1599 int vid
= ugenp
->ug_dev_data
->dev_descr
->idVendor
;
1600 int pid
= ugenp
->ug_dev_data
->dev_descr
->idProduct
;
1603 ugen_minor_t minor_code
, minor_code_base
;
1604 int owns_device
= (usb_owns_device(ugenp
->ug_dip
) ?
1605 UGEN_OWNS_DEVICE
: 0);
1607 usb_get_ep_index(ep_descr
->bEndpointAddress
);
1609 ep_descr
->bEndpointAddress
& USB_EP_NUM_MASK
;
1611 ep_descr
->bmAttributes
& USB_EP_ATTR_MASK
;
1613 ep_descr
->bEndpointAddress
& USB_EP_DIR_IN
;
1615 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
1616 "ugen_epxs_minor_nodes_create: "
1617 "cfgval=%d cfgidx=%d if=%d alt=%d ep=0x%x",
1618 cfgval
, cfgidx
, iface
, alt
, ep_addr
);
1620 if (ugenp
->ug_instance
>= UGEN_MINOR_INSTANCE_LIMIT(ugenp
)) {
1621 USB_DPRINTF_L0(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
1622 "instance number too high (%d)", ugenp
->ug_instance
);
1624 return (USB_FAILURE
);
1627 /* create stat and xfer minor node */
1629 ((ugen_minor_t
)cfgval
) << UGEN_MINOR_CFGVAL_SHIFT
|
1630 ((ugen_minor_t
)cfgidx
) << UGEN_MINOR_CFGIDX_SHIFT
|
1631 iface
<< UGEN_MINOR_IF_SHIFT
|
1632 alt
<< UGEN_MINOR_ALT_SHIFT
|
1633 ep_index
<< UGEN_MINOR_EPIDX_SHIFT
| owns_device
;
1634 minor_code
= minor_code_base
| UGEN_MINOR_EP_XFER_NODE
;
1636 minor_index
= ugen_minor_index_create(ugenp
, minor_code
);
1637 if (minor_index
< 0) {
1638 USB_DPRINTF_L1(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
1639 "too many minor nodes, "
1640 "cannot create %d.%d.%d.%x",
1641 cfgval
, iface
, alt
, ep_addr
);
1642 /* carry on regardless */
1644 return (USB_SUCCESS
);
1646 minor
= (minor_index
<< UGEN_MINOR_IDX_SHIFT(ugenp
)) |
1647 ugenp
->ug_instance
<< UGEN_MINOR_INSTANCE_SHIFT(ugenp
);
1649 if (ep_type
== USB_EP_ATTR_CONTROL
) {
1652 type
= (ep_dir
& USB_EP_DIR_IN
) ? "in" : "out";
1656 * xfer ep node name:
1657 * vid.pid.[in|out|cntrl].[<cfg>.][if<iface>.][<alt>.]<ep addr>
1659 if ((ep_addr
== 0) && owns_device
) {
1660 (void) sprintf(node_name
, "%x.%x.%s%d",
1661 vid
, pid
, type
, ep_addr
);
1662 } else if (cfgidx
== 0 && alt
== 0) {
1663 (void) sprintf(node_name
, "%x.%x.if%d%s%d",
1664 vid
, pid
, iface
, type
, ep_addr
);
1665 } else if (cfgidx
== 0 && alt
!= 0) {
1666 (void) sprintf(node_name
, "%x.%x.if%d.%d%s%d",
1667 vid
, pid
, iface
, alt
, type
, ep_addr
);
1668 } else if (cfgidx
!= 0 && alt
== 0) {
1669 (void) sprintf(node_name
, "%x.%x.cfg%dif%d%s%d",
1670 vid
, pid
, cfgval
, iface
, type
, ep_addr
);
1671 } else if (cfgidx
!= 0 && alt
!= 0) {
1672 (void) sprintf(node_name
, "%x.%x.cfg%dif%d.%d%s%d",
1673 vid
, pid
, cfgval
, iface
, alt
,
1677 USB_DPRINTF_L3(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
1678 "minor=0x%x index=%d code=0x%" PRIx64
" name=%s",
1679 minor
, minor_index
, minor_code
, node_name
);
1681 ASSERT(minor
< L_MAXMIN
);
1683 if ((ddi_create_minor_node(ugenp
->ug_dip
, node_name
,
1684 S_IFCHR
, minor
, DDI_NT_UGEN
, 0)) != DDI_SUCCESS
) {
1686 return (USB_FAILURE
);
1689 ugen_store_devt(ugenp
, minor
);
1691 minor_code
= minor_code_base
| UGEN_MINOR_EP_STAT_NODE
;
1692 minor_index
= ugen_minor_index_create(ugenp
, minor_code
);
1693 if (minor_index
< 0) {
1694 USB_DPRINTF_L1(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
1695 "too many minor nodes, "
1696 "cannot create %d.%d.%d.%x stat",
1698 ep_descr
->bEndpointAddress
);
1699 /* carry on regardless */
1701 return (USB_SUCCESS
);
1703 minor
= (minor_index
<< UGEN_MINOR_IDX_SHIFT(ugenp
)) |
1704 ugenp
->ug_instance
<< UGEN_MINOR_INSTANCE_SHIFT(ugenp
);
1706 (void) strcat(node_name
, "stat");
1708 USB_DPRINTF_L3(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
1709 "minor=0x%x index=%d code=0x%" PRIx64
" name=%s",
1710 minor
, minor_index
, minor_code
, node_name
);
1712 ASSERT(minor
< L_MAXMIN
);
1714 if ((ddi_create_minor_node(ugenp
->ug_dip
, node_name
,
1715 S_IFCHR
, minor
, DDI_NT_UGEN
, 0)) != DDI_SUCCESS
) {
1717 return (USB_FAILURE
);
1720 ugen_store_devt(ugenp
, minor
);
1722 return (USB_SUCCESS
);
1727 * close all non-default pipes and drain default pipe
1730 ugen_epx_shutdown(ugen_state_t
*ugenp
)
1734 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1735 "ugen_epx_shutdown:");
1737 for (i
= 0; i
< UGEN_N_ENDPOINTS
; i
++) {
1738 ugen_ep_t
*epp
= &ugenp
->ug_ep
[i
];
1739 mutex_enter(&epp
->ep_mutex
);
1740 if (epp
->ep_state
!= UGEN_EP_STATE_NONE
) {
1741 mutex_exit(&epp
->ep_mutex
);
1742 (void) usb_serialize_access(epp
->ep_ser_cookie
,
1744 (void) ugen_epx_close_pipe(ugenp
, epp
);
1745 usb_release_access(epp
->ep_ser_cookie
);
1747 mutex_exit(&epp
->ep_mutex
);
1754 * find cfg index corresponding to cfg value
1757 ugen_cfgval2idx(ugen_state_t
*ugenp
, uint_t cfgval
)
1759 usb_cfg_data_t
*dev_cfg
= ugenp
->ug_dev_data
->dev_cfg
;
1762 for (cfgidx
= 0; cfgidx
< ugenp
->ug_dev_data
->dev_n_cfg
; cfgidx
++) {
1763 dev_cfg
= &ugenp
->ug_dev_data
->dev_cfg
[cfgidx
];
1764 if (cfgval
== dev_cfg
->cfg_descr
.bConfigurationValue
) {
1770 ASSERT(cfgidx
< ugenp
->ug_dev_data
->dev_n_cfg
);
1777 * check if any node is open
1780 ugen_epxs_check_open_nodes(ugen_state_t
*ugenp
)
1784 for (i
= 1; i
< UGEN_N_ENDPOINTS
; i
++) {
1785 ugen_ep_t
*epp
= &ugenp
->ug_ep
[i
];
1787 mutex_enter(&epp
->ep_mutex
);
1789 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1790 "ugen_epxs_check_open_nodes: epp=%d, ep_state=0x%x",
1793 if (epp
->ep_state
& UGEN_EP_STATE_XS_OPEN
) {
1794 mutex_exit(&epp
->ep_mutex
);
1796 return (USB_SUCCESS
);
1798 mutex_exit(&epp
->ep_mutex
);
1801 return (USB_FAILURE
);
1806 * check if we can switch alternate
1809 ugen_epxs_check_alt_switch(ugen_state_t
*ugenp
, uchar_t iface
, uchar_t cfgidx
)
1813 for (i
= 1; i
< UGEN_N_ENDPOINTS
; i
++) {
1814 ugen_ep_t
*epp
= &ugenp
->ug_ep
[i
];
1816 mutex_enter(&epp
->ep_mutex
);
1818 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1819 "ugen_epxs_check_alt_switch: epp=%d, ep_state=0x%x",
1823 * if the endpoint is open and part of this cfg and interface
1824 * then we cannot switch alternates
1826 if ((epp
->ep_state
& UGEN_EP_STATE_XS_OPEN
) &&
1827 (epp
->ep_cfgidx
== cfgidx
) &&
1828 (epp
->ep_if
== iface
)) {
1829 mutex_exit(&epp
->ep_mutex
);
1831 return (USB_FAILURE
);
1833 mutex_exit(&epp
->ep_mutex
);
1836 return (USB_SUCCESS
);
1841 * implicit switch to new cfg and alt
1842 * If a crummy device fails usb_get_cfg or usb_get_alt_if, we carry on
1843 * regardless so at least the device can be opened.
1846 ugen_epxs_switch_cfg_alt(ugen_state_t
*ugenp
, ugen_ep_t
*epp
, dev_t dev
)
1848 int rval
= USB_SUCCESS
;
1850 uint_t new_alt
= UGEN_MINOR_ALT(ugenp
, dev
);
1851 uint_t new_if
= UGEN_MINOR_IF(ugenp
, dev
);
1852 uint_t cur_if
= epp
->ep_if
;
1853 uint_t new_cfgidx
= UGEN_MINOR_CFGIDX(ugenp
, dev
);
1858 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1859 "ugen_epxs_switch_cfg_alt: old cfgidx=%d, if=%d alt=%d",
1860 epp
->ep_cfgidx
, epp
->ep_if
, epp
->ep_alt
);
1861 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1862 "new cfgidx=%d, if=%d alt=%d ep_state=0x%x",
1863 new_cfgidx
, new_if
, new_alt
, epp
->ep_state
);
1865 /* no need to switch if there is only 1 cfg, 1 iface and no alts */
1866 if ((new_if
== 0) && (new_alt
== 0) &&
1867 (ugenp
->ug_dev_data
->dev_n_cfg
== 1) &&
1868 (ugenp
->ug_dev_data
->dev_cfg
[0].cfg_n_if
== 1) &&
1869 (ugenp
->ug_dev_data
->
1870 dev_cfg
[0].cfg_if
[new_if
].if_n_alt
== 1)) {
1871 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
1872 "no need for switching: n_cfg=%d n_alt=%d",
1873 ugenp
->ug_dev_data
->dev_n_cfg
,
1874 ugenp
->ug_dev_data
->
1875 dev_cfg
[0].cfg_if
[new_if
].if_n_alt
);
1877 ASSERT(epp
->ep_alt
== new_alt
);
1878 ASSERT(epp
->ep_cfgidx
== new_cfgidx
);
1879 ASSERT(epp
->ep_if
== new_if
);
1884 /* no switch for default endpoint */
1885 if (epp
->ep_descr
.bEndpointAddress
== 0) {
1890 mutex_exit(&epp
->ep_mutex
);
1891 if ((ugenp
->ug_dev_data
->dev_n_cfg
> 1) &&
1892 usb_get_cfg(ugenp
->ug_dip
, &cfgval
,
1893 USB_FLAGS_SLEEP
) == USB_SUCCESS
) {
1895 mutex_enter(&epp
->ep_mutex
);
1897 cur_cfgidx
= ugen_cfgval2idx(ugenp
, cfgval
);
1899 if (new_cfgidx
!= cur_cfgidx
) {
1900 mutex_exit(&epp
->ep_mutex
);
1903 * we can't change config if any node
1906 if (ugen_epxs_check_open_nodes(ugenp
) ==
1908 mutex_enter(&epp
->ep_mutex
);
1914 * we are going to do this synchronously to
1916 * This should never hang forever.
1918 if ((rval
= usb_set_cfg(ugenp
->ug_dip
,
1919 new_cfgidx
, USB_FLAGS_SLEEP
, NULL
,
1920 NULL
)) != USB_SUCCESS
) {
1921 USB_DPRINTF_L2(UGEN_PRINT_XFER
,
1923 "implicit set cfg (%" PRId64
1925 UGEN_MINOR_CFGIDX(ugenp
, dev
), rval
);
1926 mutex_enter(&epp
->ep_mutex
);
1930 mutex_enter(&epp
->ep_mutex
);
1931 epp
->ep_if
= (uchar_t
)new_if
;
1934 epp
->ep_cfgidx
= (uchar_t
)new_cfgidx
;
1936 mutex_exit(&epp
->ep_mutex
);
1940 * implicitly switch to new alternate if
1941 * - we have not switched configuration (if we
1942 * we switched config, the alternate must be 0)
1944 * - if the device supports get_alternate iface
1946 if ((switched
&& (new_alt
> 0)) ||
1947 ((ugenp
->ug_dev_data
->dev_cfg
[new_cfgidx
].
1948 cfg_if
[new_if
].if_n_alt
> 1) &&
1949 (usb_get_alt_if(ugenp
->ug_dip
, new_if
, &alt
,
1950 USB_FLAGS_SLEEP
) == USB_SUCCESS
))) {
1951 if (switched
|| (alt
!= new_alt
)) {
1952 if (ugen_epxs_check_alt_switch(ugenp
, cur_if
,
1953 new_cfgidx
) != USB_SUCCESS
) {
1954 mutex_enter(&epp
->ep_mutex
);
1958 if ((rval
= usb_set_alt_if(ugenp
->ug_dip
, new_if
,
1959 new_alt
, USB_FLAGS_SLEEP
, NULL
, NULL
)) !=
1961 USB_DPRINTF_L2(UGEN_PRINT_XFER
,
1963 "implicit set new alternate "
1964 "(%d) failed (%d)", new_alt
, rval
);
1965 mutex_enter(&epp
->ep_mutex
);
1972 mutex_enter(&epp
->ep_mutex
);
1973 epp
->ep_alt
= (uchar_t
)new_alt
;
1974 ugen_update_ep_descr(ugenp
, epp
);
1981 * update endpoint descriptor in ugen_ep structure after
1982 * switching configuration or alternate
1985 ugen_update_ep_descr(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
1987 usb_cfg_data_t
*dev_cfg
= ugenp
->ug_dev_data
->dev_cfg
;
1988 usb_if_data_t
*if_data
;
1989 usb_alt_if_data_t
*alt_if_data
;
1990 usb_ep_data_t
*ep_data
;
1993 dev_cfg
= &ugenp
->ug_dev_data
->dev_cfg
[epp
->ep_cfgidx
];
1994 if_data
= &dev_cfg
->cfg_if
[epp
->ep_if
];
1995 alt_if_data
= &if_data
->if_alt
[epp
->ep_alt
];
1996 for (ep
= 0; ep
< alt_if_data
->altif_n_ep
; ep
++) {
1997 ep_data
= &alt_if_data
->altif_ep
[ep
];
1998 if (usb_get_ep_index(ep_data
->ep_descr
.
1999 bEndpointAddress
) ==
2000 usb_get_ep_index(epp
->ep_descr
.
2001 bEndpointAddress
)) {
2002 epp
->ep_descr
= ep_data
->ep_descr
;
2003 (void) usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION
,
2004 ugenp
->ug_dip
, ep_data
, &epp
->ep_xdescr
);
2013 * Xfer endpoint management
2015 * open an endpoint for xfers
2017 * Return values: errno
2020 ugen_epx_open(ugen_state_t
*ugenp
, dev_t dev
, int flag
)
2022 ugen_ep_t
*epp
= &ugenp
->ug_ep
[UGEN_MINOR_EPIDX(ugenp
, dev
)];
2025 mutex_enter(&epp
->ep_mutex
);
2027 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2028 "ugen_epx_open: minor=0x%x flag=0x%x ep_state=0x%x",
2029 getminor(dev
), flag
, epp
->ep_state
);
2031 ASSERT(epp
->ep_state
& UGEN_EP_STATE_ACTIVE
);
2033 /* implicit switch to new cfg & alt */
2034 if ((epp
->ep_state
& UGEN_EP_STATE_XFER_OPEN
) != 0) {
2035 mutex_exit(&epp
->ep_mutex
);
2039 if ((rval
= ugen_epxs_switch_cfg_alt(ugenp
, epp
, dev
)) ==
2041 rval
= ugen_epx_open_pipe(ugenp
, epp
, flag
);
2044 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2045 "ugen_epx_open: state=0x%x", epp
->ep_state
);
2047 ASSERT(epp
->ep_state
& UGEN_EP_STATE_ACTIVE
);
2048 epp
->ep_done
= epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
2050 mutex_exit(&epp
->ep_mutex
);
2052 return (usb_rval2errno(rval
));
2057 * close an endpoint for xfers
2060 ugen_epx_close(ugen_state_t
*ugenp
, dev_t dev
, int flag
)
2062 ugen_ep_t
*epp
= &ugenp
->ug_ep
[UGEN_MINOR_EPIDX(ugenp
, dev
)];
2064 mutex_enter(&epp
->ep_mutex
);
2065 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2066 "ugen_epx_close: dev=0x%lx flag=0x%x state=0x%x", dev
, flag
,
2068 mutex_exit(&epp
->ep_mutex
);
2070 ugen_epx_close_pipe(ugenp
, epp
);
2072 mutex_enter(&epp
->ep_mutex
);
2073 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2074 "ugen_epx_close: state=0x%x", epp
->ep_state
);
2075 ASSERT(epp
->ep_state
& UGEN_EP_STATE_ACTIVE
);
2076 ASSERT(epp
->ep_bp
== NULL
);
2077 ASSERT(epp
->ep_done
== 0);
2078 ASSERT(epp
->ep_data
== NULL
);
2079 mutex_exit(&epp
->ep_mutex
);
2084 * open pipe for this endpoint
2085 * If the pipe is an interrupt IN pipe, start polling immediately
2088 ugen_epx_open_pipe(ugen_state_t
*ugenp
, ugen_ep_t
*epp
, int flag
)
2090 int rval
= USB_SUCCESS
;
2092 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2093 "ugen_epx_open_pipe: epp=0x%p flag=%d state=0x%x",
2094 (void *)epp
, flag
, epp
->ep_state
);
2096 epp
->ep_state
|= UGEN_EP_STATE_XFER_OPEN
;
2097 epp
->ep_xfer_oflag
= flag
;
2099 /* if default pipe, just copy the handle */
2100 if ((epp
->ep_descr
.bEndpointAddress
& USB_EP_NUM_MASK
) == 0) {
2101 epp
->ep_ph
= ugenp
->ug_dev_data
->dev_default_ph
;
2103 mutex_exit(&epp
->ep_mutex
);
2105 rval
= usb_pipe_xopen(ugenp
->ug_dip
,
2106 &epp
->ep_xdescr
, &epp
->ep_pipe_policy
,
2107 USB_FLAGS_SLEEP
, &epp
->ep_ph
);
2109 mutex_enter(&epp
->ep_mutex
);
2111 if (rval
== USB_SUCCESS
) {
2112 (void) usb_pipe_set_private(epp
->ep_ph
,
2116 * if interrupt IN pipe, and one xfer mode
2117 * has not been set, start polling immediately
2119 if ((UGEN_XFER_TYPE(epp
) == USB_EP_ATTR_INTR
) &&
2120 (!(epp
->ep_one_xfer
)) &&
2121 (UGEN_XFER_DIR(epp
) == USB_EP_DIR_IN
)) {
2122 if ((rval
= ugen_epx_intr_IN_start_polling(
2123 ugenp
, epp
)) != USB_SUCCESS
) {
2125 mutex_exit(&epp
->ep_mutex
);
2126 usb_pipe_close(ugenp
->ug_dip
,
2127 epp
->ep_ph
, USB_FLAGS_SLEEP
,
2129 mutex_enter(&epp
->ep_mutex
);
2134 UGEN_EP_STATE_INTR_IN_POLLING_ON
;
2136 /* allow for about 1 sec of data */
2138 (1000/epp
->ep_descr
.bInterval
) *
2139 epp
->ep_descr
.wMaxPacketSize
;
2143 /* set ep_buf_limit for isoc IN pipe */
2144 if ((UGEN_XFER_TYPE(epp
) == USB_EP_ATTR_ISOCH
) &&
2145 (UGEN_XFER_DIR(epp
) == USB_EP_DIR_IN
)) {
2150 UGEN_PKT_SIZE(epp
->ep_descr
.wMaxPacketSize
);
2153 * wMaxPacketSize bits 10..0 specifies maximum
2154 * packet size, which can hold 1024 bytes. If
2155 * bits 12..11 is non zero, max_size will be
2156 * greater than 1024 and the endpoint is a
2157 * high-bandwidth endpoint.
2159 if (max_size
<= 1024) {
2161 * allowing about 1s data of highspeed and 8s
2162 * data of full speed device
2164 framecnt
= ugen_isoc_buf_limit
;
2165 epp
->ep_buf_limit
= framecnt
*
2169 * allow for about 333 ms data for high-speed
2170 * high-bandwidth data
2172 framecnt
= ugen_isoc_buf_limit
/3;
2174 framecnt
* max_size
* 8;
2177 epp
->ep_isoc_in_inited
= 0;
2182 if (rval
!= USB_SUCCESS
) {
2183 epp
->ep_state
&= ~(UGEN_EP_STATE_XFER_OPEN
|
2184 UGEN_EP_STATE_INTR_IN_POLLING_ON
);
2192 * close an endpoint pipe
2195 ugen_epx_close_pipe(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
2197 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2198 "ugen_epx_close_pipe: epp=0x%p", (void *)epp
);
2200 mutex_enter(&epp
->ep_mutex
);
2201 if (epp
->ep_state
& UGEN_EP_STATE_XFER_OPEN
) {
2203 /* free isoc pipe private data ep_isoc_info.isoc_pkt_descr. */
2204 if (UGEN_XFER_TYPE(epp
) == USB_EP_ATTR_ISOCH
) {
2208 if (UGEN_XFER_DIR(epp
) == USB_EP_DIR_IN
&&
2210 UGEN_EP_STATE_ISOC_IN_POLLING_ON
)) {
2211 mutex_exit(&epp
->ep_mutex
);
2212 usb_pipe_stop_isoc_polling(epp
->ep_ph
,
2214 mutex_enter(&epp
->ep_mutex
);
2217 if (epp
->ep_isoc_info
.isoc_pkt_descr
) {
2218 n_pkt
= epp
->ep_isoc_info
.
2220 len
= sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
;
2222 kmem_free(epp
->ep_isoc_info
.isoc_pkt_descr
,
2225 epp
->ep_isoc_info
.isoc_pkt_descr
= NULL
;
2227 epp
->ep_isoc_in_inited
= 0;
2232 epp
->ep_state
&= ~(UGEN_EP_STATE_XFER_OPEN
|
2233 UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED
|
2234 UGEN_EP_STATE_INTR_IN_POLLING_ON
|
2235 UGEN_EP_STATE_ISOC_IN_POLLING_IS_STOPPED
|
2236 UGEN_EP_STATE_ISOC_IN_POLLING_ON
);
2238 if (epp
->ep_ph
== ugenp
->ug_dev_data
->dev_default_ph
) {
2239 mutex_exit(&epp
->ep_mutex
);
2241 (void) usb_pipe_drain_reqs(ugenp
->ug_dip
,
2242 epp
->ep_ph
, 0, USB_FLAGS_SLEEP
,
2244 mutex_enter(&epp
->ep_mutex
);
2246 mutex_exit(&epp
->ep_mutex
);
2247 usb_pipe_close(ugenp
->ug_dip
,
2248 epp
->ep_ph
, USB_FLAGS_SLEEP
, NULL
, NULL
);
2250 mutex_enter(&epp
->ep_mutex
);
2254 freemsg(epp
->ep_data
);
2256 epp
->ep_data
= NULL
;
2258 ASSERT(epp
->ep_ph
== NULL
);
2259 ASSERT(epp
->ep_data
== NULL
);
2260 mutex_exit(&epp
->ep_mutex
);
2265 * start endpoint xfer
2267 * We first serialize at endpoint level for only one request at the time
2269 * Return values: errno
2272 ugen_epx_req(ugen_state_t
*ugenp
, struct buf
*bp
)
2274 dev_t dev
= bp
->b_edev
;
2275 ugen_ep_t
*epp
= &ugenp
->ug_ep
[UGEN_MINOR_EPIDX(ugenp
, dev
)];
2276 boolean_t wait
= B_FALSE
;
2279 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2280 "ugen_epx_req: bp=0x%p dev=0x%lx", (void *)bp
, dev
);
2282 /* single thread per endpoint, one request at the time */
2283 if (usb_serialize_access(epp
->ep_ser_cookie
, USB_WAIT_SIG
, 0) <=
2289 mutex_enter(&ugenp
->ug_mutex
);
2290 switch (ugenp
->ug_dev_state
) {
2291 case USB_DEV_ONLINE
:
2294 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT
:
2295 case USB_DEV_DISCONNECTED
:
2296 mutex_enter(&epp
->ep_mutex
);
2297 epp
->ep_lcmd_status
= USB_LC_STAT_DISCONNECTED
;
2298 mutex_exit(&epp
->ep_mutex
);
2302 case USB_UGEN_DEV_UNAVAILABLE_RESUME
:
2303 case USB_DEV_SUSPENDED
:
2304 mutex_enter(&epp
->ep_mutex
);
2305 epp
->ep_lcmd_status
= USB_LC_STAT_SUSPENDED
;
2306 mutex_exit(&epp
->ep_mutex
);
2311 mutex_enter(&epp
->ep_mutex
);
2312 epp
->ep_lcmd_status
= USB_LC_STAT_HW_ERR
;
2313 mutex_exit(&epp
->ep_mutex
);
2320 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2321 "ugen_epx_req: lcmd_status=0x%x", epp
->ep_lcmd_status
);
2324 mutex_exit(&ugenp
->ug_mutex
);
2327 usb_release_access(epp
->ep_ser_cookie
);
2332 mutex_enter(&epp
->ep_mutex
);
2333 ASSERT(epp
->ep_state
& UGEN_EP_STATE_XS_OPEN
);
2337 switch (epp
->ep_descr
.bmAttributes
& USB_EP_ATTR_MASK
) {
2338 case USB_EP_ATTR_CONTROL
:
2339 rval
= ugen_epx_ctrl_req(ugenp
, epp
, bp
, &wait
);
2342 case USB_EP_ATTR_BULK
:
2343 rval
= ugen_epx_bulk_req(ugenp
, epp
, bp
, &wait
);
2346 case USB_EP_ATTR_INTR
:
2347 if (bp
->b_flags
& B_READ
) {
2348 rval
= ugen_epx_intr_IN_req(ugenp
, epp
, bp
, &wait
);
2350 rval
= ugen_epx_intr_OUT_req(ugenp
, epp
, bp
, &wait
);
2354 case USB_EP_ATTR_ISOCH
:
2355 if (bp
->b_flags
& B_READ
) {
2356 rval
= ugen_epx_isoc_IN_req(ugenp
, epp
, bp
, &wait
);
2358 rval
= ugen_epx_isoc_OUT_req(ugenp
, epp
, bp
, &wait
);
2363 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
2364 rval
= USB_INVALID_REQUEST
;
2367 /* if the xfer could not immediately be completed, block here */
2368 if ((rval
== USB_SUCCESS
) && wait
) {
2369 while (!epp
->ep_done
) {
2370 if ((cv_wait_sig(&epp
->ep_wait_cv
,
2371 &epp
->ep_mutex
) <= 0) && !epp
->ep_done
) {
2372 USB_DPRINTF_L2(UGEN_PRINT_XFER
,
2374 "ugen_epx_req: interrupted ep=0x%" PRIx64
,
2375 UGEN_MINOR_EPIDX(ugenp
, dev
));
2378 * blow away the request except for dflt pipe
2379 * (this is prevented in USBA)
2381 mutex_exit(&epp
->ep_mutex
);
2382 usb_pipe_reset(ugenp
->ug_dip
, epp
->ep_ph
,
2383 USB_FLAGS_SLEEP
, NULL
, NULL
);
2384 (void) usb_pipe_drain_reqs(ugenp
->ug_dip
,
2386 USB_FLAGS_SLEEP
, NULL
, NULL
);
2388 mutex_enter(&epp
->ep_mutex
);
2390 if (geterror(bp
) == 0) {
2391 bioerror(bp
, EINTR
);
2393 epp
->ep_lcmd_status
=
2394 USB_LC_STAT_INTERRUPTED
;
2398 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2399 "ugen_epx_req: wakeup");
2403 /* always set lcmd_status if there was a failure */
2404 if ((rval
!= USB_SUCCESS
) &&
2405 (epp
->ep_lcmd_status
== USB_LC_STAT_NOERROR
)) {
2406 epp
->ep_lcmd_status
= USB_LC_STAT_UNSPECIFIED_ERR
;
2411 mutex_exit(&epp
->ep_mutex
);
2413 usb_release_access(epp
->ep_ser_cookie
);
2414 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2415 "ugen_epx_req: done");
2417 return (usb_rval2errno(rval
));
2422 * handle control xfers
2425 ugen_epx_ctrl_req(ugen_state_t
*ugenp
, ugen_ep_t
*epp
,
2426 struct buf
*bp
, boolean_t
*wait
)
2428 usb_ctrl_req_t
*reqp
= NULL
;
2429 uchar_t
*setup
= ((uchar_t
*)(bp
->b_un
.b_addr
));
2433 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2434 "ugen_epx_ctrl_req: epp=0x%p state=0x%x bp=0x%p",
2435 (void *)epp
, epp
->ep_state
, (void *)bp
);
2437 /* is this a read following a write with setup data? */
2438 if (bp
->b_flags
& B_READ
) {
2440 int ep_len
= MBLKL(epp
->ep_data
);
2441 int len
= min(bp
->b_bcount
, ep_len
);
2443 bcopy(epp
->ep_data
->b_rptr
, bp
->b_un
.b_addr
, len
);
2444 epp
->ep_data
->b_rptr
+= len
;
2445 if (MBLKL(epp
->ep_data
) == 0) {
2446 freemsg(epp
->ep_data
);
2447 epp
->ep_data
= NULL
;
2449 bp
->b_resid
= bp
->b_bcount
- len
;
2451 bp
->b_resid
= bp
->b_bcount
;
2454 return (USB_SUCCESS
);
2457 /* discard old data if any */
2459 freemsg(epp
->ep_data
);
2460 epp
->ep_data
= NULL
;
2463 /* allocate and initialize request */
2464 wLength
= (setup
[7] << 8) | setup
[6];
2465 reqp
= usb_alloc_ctrl_req(ugenp
->ug_dip
, wLength
, USB_FLAGS_NOSLEEP
);
2467 epp
->ep_lcmd_status
= USB_LC_STAT_NO_RESOURCES
;
2469 return (USB_NO_RESOURCES
);
2472 /* assume an LE data stream */
2473 reqp
->ctrl_bmRequestType
= setup
[0];
2474 reqp
->ctrl_bRequest
= setup
[1];
2475 reqp
->ctrl_wValue
= (setup
[3] << 8) | setup
[2];
2476 reqp
->ctrl_wIndex
= (setup
[5] << 8) | setup
[4];
2477 reqp
->ctrl_wLength
= wLength
;
2478 reqp
->ctrl_timeout
= ugen_ctrl_timeout
;
2479 reqp
->ctrl_attributes
= USB_ATTRS_AUTOCLEARING
|
2480 USB_ATTRS_SHORT_XFER_OK
;
2481 reqp
->ctrl_cb
= ugen_epx_ctrl_req_cb
;
2482 reqp
->ctrl_exc_cb
= ugen_epx_ctrl_req_cb
;
2483 reqp
->ctrl_client_private
= (usb_opaque_t
)ugenp
;
2486 * is this a legal request? No accesses to device are
2487 * allowed if we don't own the device
2489 if (((reqp
->ctrl_bmRequestType
& USB_DEV_REQ_RCPT_MASK
) ==
2490 USB_DEV_REQ_RCPT_DEV
) &&
2491 (((reqp
->ctrl_bmRequestType
& USB_DEV_REQ_DIR_MASK
) ==
2492 USB_DEV_REQ_HOST_TO_DEV
) &&
2493 (usb_owns_device(ugenp
->ug_dip
) == B_FALSE
))) {
2494 rval
= USB_INVALID_PERM
;
2495 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
2500 /* filter out set_cfg and set_if standard requests */
2501 if ((reqp
->ctrl_bmRequestType
& USB_DEV_REQ_TYPE_MASK
) ==
2502 USB_DEV_REQ_TYPE_STANDARD
) {
2503 switch (reqp
->ctrl_bRequest
) {
2504 case USB_REQ_SET_CFG
:
2505 case USB_REQ_SET_IF
:
2506 rval
= USB_INVALID_REQUEST
;
2507 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
2516 /* is this from host to device? */
2517 if (((reqp
->ctrl_bmRequestType
& USB_DEV_REQ_DIR_MASK
) ==
2518 USB_DEV_REQ_HOST_TO_DEV
) && reqp
->ctrl_wLength
) {
2519 if (((bp
->b_bcount
- UGEN_SETUP_PKT_SIZE
) - wLength
) != 0) {
2520 rval
= USB_INVALID_REQUEST
;
2521 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
2525 bcopy(bp
->b_un
.b_addr
+ UGEN_SETUP_PKT_SIZE
,
2526 reqp
->ctrl_data
->b_wptr
, wLength
);
2527 reqp
->ctrl_data
->b_wptr
+= wLength
;
2528 } else if ((reqp
->ctrl_bmRequestType
& USB_DEV_REQ_DIR_MASK
) ==
2529 USB_DEV_REQ_DEV_TO_HOST
) {
2530 if (bp
->b_bcount
!= UGEN_SETUP_PKT_SIZE
) {
2531 rval
= USB_INVALID_REQUEST
;
2532 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
2538 /* submit the request */
2539 mutex_exit(&epp
->ep_mutex
);
2540 rval
= usb_pipe_ctrl_xfer(epp
->ep_ph
, reqp
, USB_FLAGS_NOSLEEP
);
2541 mutex_enter(&epp
->ep_mutex
);
2542 if (rval
!= USB_SUCCESS
) {
2543 epp
->ep_lcmd_status
=
2544 ugen_cr2lcstat(reqp
->ctrl_completion_reason
);
2551 return (USB_SUCCESS
);
2555 usb_free_ctrl_req(reqp
);
2562 * callback for control requests, normal and exception completion
2565 ugen_epx_ctrl_req_cb(usb_pipe_handle_t ph
, usb_ctrl_req_t
*reqp
)
2567 ugen_state_t
*ugenp
= (ugen_state_t
*)reqp
->ctrl_client_private
;
2568 ugen_ep_t
*epp
= (ugen_ep_t
*)usb_pipe_get_private(ph
);
2571 epp
= &ugenp
->ug_ep
[0];
2574 mutex_enter(&epp
->ep_mutex
);
2576 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2577 "ugen_epx_ctrl_req_cb:\n\t"
2578 "epp=0x%p state=0x%x ph=0x%p reqp=0x%p cr=%d cb=0x%x",
2579 (void *)epp
, epp
->ep_state
, (void *)ph
, (void *)reqp
,
2580 reqp
->ctrl_completion_reason
, reqp
->ctrl_cb_flags
);
2582 ASSERT((reqp
->ctrl_cb_flags
& USB_CB_INTR_CONTEXT
) == 0);
2584 /* save any data for the next read */
2585 switch (reqp
->ctrl_completion_reason
) {
2587 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
2590 case USB_CR_PIPE_RESET
:
2594 epp
->ep_lcmd_status
=
2595 ugen_cr2lcstat(reqp
->ctrl_completion_reason
);
2597 bioerror(epp
->ep_bp
, EIO
);
2603 if (reqp
->ctrl_data
) {
2604 ASSERT(epp
->ep_data
== NULL
);
2605 epp
->ep_data
= reqp
->ctrl_data
;
2606 reqp
->ctrl_data
= NULL
;
2609 cv_signal(&epp
->ep_wait_cv
);
2610 mutex_exit(&epp
->ep_mutex
);
2612 usb_free_ctrl_req(reqp
);
2614 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2615 "ugen_epx_ctrl_req_cb: done");
2623 ugen_epx_bulk_req(ugen_state_t
*ugenp
, ugen_ep_t
*epp
,
2624 struct buf
*bp
, boolean_t
*wait
)
2627 usb_bulk_req_t
*reqp
= usb_alloc_bulk_req(ugenp
->ug_dip
,
2628 bp
->b_bcount
, USB_FLAGS_NOSLEEP
);
2630 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2631 "ugen_epx_bulk_req: epp=0x%p state=0x%x bp=0x%p",
2632 (void *)epp
, epp
->ep_state
, (void *)bp
);
2635 epp
->ep_lcmd_status
= USB_LC_STAT_NO_RESOURCES
;
2637 return (USB_NO_RESOURCES
);
2640 ASSERT(epp
->ep_state
& UGEN_EP_STATE_XS_OPEN
);
2643 * the transfer count is limited in minphys with what the HCD can
2646 reqp
->bulk_len
= bp
->b_bcount
;
2647 reqp
->bulk_timeout
= ugen_bulk_timeout
;
2648 reqp
->bulk_client_private
= (usb_opaque_t
)ugenp
;
2649 reqp
->bulk_attributes
= USB_ATTRS_AUTOCLEARING
;
2650 reqp
->bulk_cb
= ugen_epx_bulk_req_cb
;
2651 reqp
->bulk_exc_cb
= ugen_epx_bulk_req_cb
;
2653 /* copy data into bp for OUT pipes */
2654 if ((UGEN_XFER_DIR(epp
) & USB_EP_DIR_IN
) == 0) {
2655 bcopy(epp
->ep_bp
->b_un
.b_addr
, reqp
->bulk_data
->b_rptr
,
2657 reqp
->bulk_data
->b_wptr
+= bp
->b_bcount
;
2659 reqp
->bulk_attributes
|= USB_ATTRS_SHORT_XFER_OK
;
2662 mutex_exit(&epp
->ep_mutex
);
2663 if ((rval
= usb_pipe_bulk_xfer(epp
->ep_ph
, reqp
,
2664 USB_FLAGS_NOSLEEP
)) != USB_SUCCESS
) {
2665 mutex_enter(&epp
->ep_mutex
);
2666 epp
->ep_lcmd_status
=
2667 ugen_cr2lcstat(reqp
->bulk_completion_reason
);
2668 usb_free_bulk_req(reqp
);
2671 mutex_enter(&epp
->ep_mutex
);
2673 *wait
= (rval
== USB_SUCCESS
) ? B_TRUE
: B_FALSE
;
2680 * normal and exception bulk request callback
2683 ugen_epx_bulk_req_cb(usb_pipe_handle_t ph
, usb_bulk_req_t
*reqp
)
2685 ugen_state_t
*ugenp
= (ugen_state_t
*)reqp
->bulk_client_private
;
2686 ugen_ep_t
*epp
= (ugen_ep_t
*)usb_pipe_get_private(ph
);
2688 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2689 "ugen_epx_bulk_req_cb: ph=0x%p reqp=0x%p cr=%d cb=0x%x",
2690 (void *)ph
, (void *)reqp
, reqp
->bulk_completion_reason
,
2691 reqp
->bulk_cb_flags
);
2693 ASSERT((reqp
->bulk_cb_flags
& USB_CB_INTR_CONTEXT
) == 0);
2695 /* epp might be NULL if we are closing the pipe */
2697 mutex_enter(&epp
->ep_mutex
);
2698 if (epp
->ep_bp
&& reqp
->bulk_data
) {
2699 int len
= min(MBLKL(reqp
->bulk_data
),
2700 epp
->ep_bp
->b_bcount
);
2701 if (UGEN_XFER_DIR(epp
) & USB_EP_DIR_IN
) {
2703 bcopy(reqp
->bulk_data
->b_rptr
,
2704 epp
->ep_bp
->b_un
.b_addr
, len
);
2705 epp
->ep_bp
->b_resid
=
2706 epp
->ep_bp
->b_bcount
- len
;
2709 epp
->ep_bp
->b_resid
=
2710 epp
->ep_bp
->b_bcount
- len
;
2713 switch (reqp
->bulk_completion_reason
) {
2715 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
2718 case USB_CR_PIPE_RESET
:
2722 epp
->ep_lcmd_status
=
2723 ugen_cr2lcstat(reqp
->bulk_completion_reason
);
2725 bioerror(epp
->ep_bp
, EIO
);
2729 cv_signal(&epp
->ep_wait_cv
);
2730 mutex_exit(&epp
->ep_mutex
);
2733 usb_free_bulk_req(reqp
);
2738 * handle intr IN xfers
2741 ugen_epx_intr_IN_req(ugen_state_t
*ugenp
, ugen_ep_t
*epp
,
2742 struct buf
*bp
, boolean_t
*wait
)
2745 int rval
= USB_SUCCESS
;
2747 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2748 "ugen_epx_intr_IN_req: epp=0x%p state=0x%x bp=0x%p",
2749 (void *)epp
, epp
->ep_state
, (void *)bp
);
2753 /* can we satisfy this read? */
2755 len
= min(MBLKL(epp
->ep_data
),
2760 * if polling not active, restart, and return failure
2761 * immediately unless one xfer mode has been requested
2762 * if there is some data, return a short read
2764 if ((epp
->ep_state
& UGEN_EP_STATE_INTR_IN_POLLING_ON
) == 0) {
2766 if (!epp
->ep_one_xfer
) {
2768 if (epp
->ep_lcmd_status
==
2769 USB_LC_STAT_NOERROR
) {
2770 epp
->ep_lcmd_status
=
2771 USB_LC_STAT_INTR_BUF_FULL
;
2774 if (ugen_epx_intr_IN_start_polling(ugenp
,
2775 epp
) != USB_SUCCESS
) {
2776 epp
->ep_lcmd_status
=
2777 USB_LC_STAT_INTR_POLLING_FAILED
;
2779 if (epp
->ep_one_xfer
) {
2783 } else if (epp
->ep_data
&& (len
< bp
->b_bcount
)) {
2784 bcopy(epp
->ep_data
->b_rptr
, bp
->b_un
.b_addr
, len
);
2785 bp
->b_resid
= bp
->b_bcount
- len
;
2786 epp
->ep_data
->b_rptr
+= len
;
2793 * if there is data or FNDELAY, return available data
2795 if ((len
>= bp
->b_bcount
) ||
2796 (epp
->ep_xfer_oflag
& (FNDELAY
| FNONBLOCK
))) {
2798 bcopy(epp
->ep_data
->b_rptr
, bp
->b_un
.b_addr
, len
);
2799 epp
->ep_data
->b_rptr
+= len
;
2800 bp
->b_resid
= bp
->b_bcount
- len
;
2802 bp
->b_resid
= bp
->b_bcount
;
2805 /* otherwise just wait for data */
2810 if (epp
->ep_data
&& (epp
->ep_data
->b_rptr
== epp
->ep_data
->b_wptr
)) {
2811 freemsg(epp
->ep_data
);
2812 epp
->ep_data
= NULL
;
2816 ASSERT(epp
->ep_state
& UGEN_EP_STATE_INTR_IN_POLLING_ON
);
2819 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2820 "ugen_epx_intr_IN_req end: rval=%d bcount=%lu len=%d data=0x%p",
2821 rval
, bp
->b_bcount
, len
, (void *)epp
->ep_data
);
2828 * Start polling on interrupt endpoint, synchronously
2831 ugen_epx_intr_IN_start_polling(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
2833 int rval
= USB_FAILURE
;
2834 usb_intr_req_t
*reqp
;
2838 * if polling is being stopped, we restart polling in the
2839 * interrrupt callback again
2841 if (epp
->ep_state
& UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED
) {
2845 if ((epp
->ep_state
& UGEN_EP_STATE_INTR_IN_POLLING_ON
) == 0) {
2846 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2847 "ugen_epx_intr_IN_start_polling: epp=0x%p state=0x%x",
2848 (void *)epp
, epp
->ep_state
);
2850 epp
->ep_state
|= UGEN_EP_STATE_INTR_IN_POLLING_ON
;
2851 mutex_exit(&epp
->ep_mutex
);
2853 reqp
= usb_alloc_intr_req(ugenp
->ug_dip
, 0,
2855 reqp
->intr_client_private
= (usb_opaque_t
)ugenp
;
2857 reqp
->intr_attributes
= USB_ATTRS_AUTOCLEARING
|
2858 USB_ATTRS_SHORT_XFER_OK
;
2859 mutex_enter(&epp
->ep_mutex
);
2860 if (epp
->ep_one_xfer
) {
2861 reqp
->intr_attributes
|= USB_ATTRS_ONE_XFER
;
2862 uflag
= USB_FLAGS_NOSLEEP
;
2864 uflag
= USB_FLAGS_SLEEP
;
2866 mutex_exit(&epp
->ep_mutex
);
2868 reqp
->intr_len
= epp
->ep_descr
.wMaxPacketSize
;
2869 reqp
->intr_cb
= ugen_epx_intr_IN_req_cb
;
2870 reqp
->intr_exc_cb
= ugen_epx_intr_IN_req_cb
;
2873 if ((rval
= usb_pipe_intr_xfer(epp
->ep_ph
, reqp
,
2874 uflag
)) != USB_SUCCESS
) {
2875 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2876 "ugen_epx_intr_IN_start_polling: failed %d", rval
);
2877 usb_free_intr_req(reqp
);
2879 mutex_enter(&epp
->ep_mutex
);
2880 if (rval
!= USB_SUCCESS
) {
2881 epp
->ep_state
&= ~UGEN_EP_STATE_INTR_IN_POLLING_ON
;
2892 * stop polling on an interrupt endpoint, asynchronously
2895 ugen_epx_intr_IN_stop_polling(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
2897 if ((epp
->ep_state
& UGEN_EP_STATE_INTR_IN_POLLING_ON
) &&
2898 ((epp
->ep_state
& UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED
) == 0)) {
2900 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2901 "ugen_epx_intr_IN_stop_polling: epp=0x%p state=0x%x",
2902 (void *)epp
, epp
->ep_state
);
2904 epp
->ep_state
|= UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED
;
2905 mutex_exit(&epp
->ep_mutex
);
2906 usb_pipe_stop_intr_polling(epp
->ep_ph
, USB_FLAGS_NOSLEEP
);
2907 mutex_enter(&epp
->ep_mutex
);
2916 ugen_epx_intr_IN_poll_wakeup(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
2918 if (epp
->ep_state
& UGEN_EP_STATE_INTR_IN_POLL_PENDING
) {
2919 struct pollhead
*phpp
= &epp
->ep_pollhead
;
2921 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2922 "ugen_epx_intr_IN_poll_wakeup: state=0x%x", epp
->ep_state
);
2924 epp
->ep_state
&= ~UGEN_EP_STATE_INTR_IN_POLL_PENDING
;
2925 mutex_exit(&epp
->ep_mutex
);
2926 pollwakeup(phpp
, POLLIN
);
2927 mutex_enter(&epp
->ep_mutex
);
2933 * callback functions for interrupt IN pipe
2936 ugen_epx_intr_IN_req_cb(usb_pipe_handle_t ph
, usb_intr_req_t
*reqp
)
2938 ugen_state_t
*ugenp
= (ugen_state_t
*)reqp
->intr_client_private
;
2939 ugen_ep_t
*epp
= (ugen_ep_t
*)usb_pipe_get_private(ph
);
2942 /* pipe is closing */
2947 mutex_enter(&epp
->ep_mutex
);
2949 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2950 "ugen_epx_intr_IN_req_cb:\n\t"
2951 "epp=0x%p state=0x%x ph=0x%p reqp=0x%p cr=%d cb=0x%x len=%ld",
2952 (void *)epp
, epp
->ep_state
, (void *)ph
, (void *)reqp
,
2953 reqp
->intr_completion_reason
, reqp
->intr_cb_flags
,
2954 (reqp
->intr_data
== NULL
) ? 0 :
2955 MBLKL(reqp
->intr_data
));
2957 ASSERT((reqp
->intr_cb_flags
& USB_CB_INTR_CONTEXT
) == 0);
2959 if (epp
->ep_data
&& reqp
->intr_data
) {
2962 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2963 "intr ep%x coalesce data", epp
->ep_descr
.bEndpointAddress
);
2965 /* coalesce the data into one mblk */
2966 epp
->ep_data
->b_cont
= reqp
->intr_data
;
2967 if ((mp
= msgpullup(epp
->ep_data
, -1)) != NULL
) {
2968 reqp
->intr_data
= NULL
;
2969 freemsg(epp
->ep_data
);
2972 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2973 "msgpullup failed, discard data");
2974 epp
->ep_data
->b_cont
= NULL
;
2976 } else if (reqp
->intr_data
) {
2977 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2980 epp
->ep_data
= reqp
->intr_data
;
2981 reqp
->intr_data
= NULL
;
2984 switch (reqp
->intr_completion_reason
) {
2986 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
2989 case USB_CR_PIPE_RESET
:
2990 case USB_CR_STOPPED_POLLING
:
2994 epp
->ep_lcmd_status
=
2995 ugen_cr2lcstat(reqp
->intr_completion_reason
);
2996 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
2997 "ugen_exp_intr_cb_req: lcmd_status=0x%x",
2998 epp
->ep_lcmd_status
);
3003 /* any non-zero completion reason stops polling */
3004 if ((reqp
->intr_completion_reason
) ||
3005 (epp
->ep_one_xfer
)) {
3006 epp
->ep_state
&= ~(UGEN_EP_STATE_INTR_IN_POLLING_ON
|
3007 UGEN_EP_STATE_INTR_IN_POLLING_IS_STOPPED
);
3010 /* is there a poll pending? should we stop polling? */
3012 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3013 "ugen_epx_intr_IN_req_cb: data len=0x%lx",
3014 MBLKL(epp
->ep_data
));
3016 ugen_epx_intr_IN_poll_wakeup(ugenp
, epp
);
3018 /* if there is no space left, stop polling */
3020 (MBLKL(epp
->ep_data
) >=
3021 epp
->ep_buf_limit
)) {
3022 ugen_epx_intr_IN_stop_polling(ugenp
, epp
);
3026 if (reqp
->intr_completion_reason
&& epp
->ep_bp
) {
3027 bioerror(epp
->ep_bp
, EIO
);
3029 cv_signal(&epp
->ep_wait_cv
);
3031 /* can we satisfy the read now */
3032 } else if (epp
->ep_data
&& epp
->ep_bp
&&
3033 (!epp
->ep_done
|| epp
->ep_one_xfer
)) {
3036 if ((ugen_epx_intr_IN_req(ugenp
, epp
, epp
->ep_bp
, &wait
) ==
3037 USB_SUCCESS
) && (wait
== B_FALSE
)) {
3039 cv_signal(&epp
->ep_wait_cv
);
3042 mutex_exit(&epp
->ep_mutex
);
3045 usb_free_intr_req(reqp
);
3050 * handle intr OUT xfers
3053 ugen_epx_intr_OUT_req(ugen_state_t
*ugenp
, ugen_ep_t
*epp
,
3054 struct buf
*bp
, boolean_t
*wait
)
3056 int rval
= USB_SUCCESS
;
3057 usb_intr_req_t
*reqp
;
3059 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3060 "ugen_epx_intr_OUT_req: epp=0x%p state=0x%x bp=0x%p",
3061 (void *)epp
, epp
->ep_state
, (void *)bp
);
3063 reqp
= usb_alloc_intr_req(ugenp
->ug_dip
, bp
->b_bcount
,
3066 epp
->ep_lcmd_status
= USB_LC_STAT_NO_RESOURCES
;
3068 return (USB_NO_RESOURCES
);
3071 ASSERT(epp
->ep_state
& UGEN_EP_STATE_XS_OPEN
);
3073 reqp
->intr_timeout
= ugen_intr_timeout
;
3074 reqp
->intr_client_private
= (usb_opaque_t
)ugenp
;
3075 reqp
->intr_len
= bp
->b_bcount
;
3076 reqp
->intr_attributes
= USB_ATTRS_AUTOCLEARING
;
3077 reqp
->intr_cb
= ugen_epx_intr_OUT_req_cb
;
3078 reqp
->intr_exc_cb
= ugen_epx_intr_OUT_req_cb
;
3080 /* copy data from bp */
3081 bcopy(epp
->ep_bp
->b_un
.b_addr
, reqp
->intr_data
->b_rptr
,
3083 reqp
->intr_data
->b_wptr
+= bp
->b_bcount
;
3085 mutex_exit(&epp
->ep_mutex
);
3086 if ((rval
= usb_pipe_intr_xfer(epp
->ep_ph
, reqp
,
3087 USB_FLAGS_NOSLEEP
)) != USB_SUCCESS
) {
3088 mutex_enter(&epp
->ep_mutex
);
3089 epp
->ep_lcmd_status
=
3090 ugen_cr2lcstat(reqp
->intr_completion_reason
);
3091 usb_free_intr_req(reqp
);
3094 mutex_enter(&epp
->ep_mutex
);
3096 *wait
= (rval
== USB_SUCCESS
) ? B_TRUE
: B_FALSE
;
3103 * callback functions for interrupt OUT pipe
3106 ugen_epx_intr_OUT_req_cb(usb_pipe_handle_t ph
, usb_intr_req_t
*reqp
)
3108 ugen_state_t
*ugenp
= (ugen_state_t
*)reqp
->intr_client_private
;
3109 ugen_ep_t
*epp
= (ugen_ep_t
*)usb_pipe_get_private(ph
);
3111 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3112 "ugen_epx_intr_OUT_req_cb: ph=0x%p reqp=0x%p cr=%d cb=0x%x",
3113 (void *)ph
, (void *)reqp
, reqp
->intr_completion_reason
,
3114 reqp
->intr_cb_flags
);
3116 ASSERT((reqp
->intr_cb_flags
& USB_CB_INTR_CONTEXT
) == 0);
3118 /* epp might be NULL if we are closing the pipe */
3122 mutex_enter(&epp
->ep_mutex
);
3124 len
= min(MBLKL(reqp
->intr_data
), epp
->ep_bp
->b_bcount
);
3126 epp
->ep_bp
->b_resid
= epp
->ep_bp
->b_bcount
- len
;
3128 switch (reqp
->intr_completion_reason
) {
3130 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
3133 case USB_CR_PIPE_RESET
:
3137 epp
->ep_lcmd_status
=
3139 reqp
->intr_completion_reason
);
3140 bioerror(epp
->ep_bp
, EIO
);
3144 cv_signal(&epp
->ep_wait_cv
);
3145 mutex_exit(&epp
->ep_mutex
);
3148 usb_free_intr_req(reqp
);
3153 * handle isoc IN xfers
3156 ugen_epx_isoc_IN_req(ugen_state_t
*ugenp
, ugen_ep_t
*epp
,
3157 struct buf
*bp
, boolean_t
*wait
)
3159 int rval
= USB_SUCCESS
;
3160 ugen_isoc_pkt_descr_t
*pkt_descr
;
3162 uint_t pkts_len
, len
= 0;
3164 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3165 "ugen_epx_isoc_IN_req: epp=0x%p state=0x%x bp=0x%p",
3166 (void *)epp
, epp
->ep_state
, (void *)bp
);
3170 /* check if the isoc in pkt info has been initialized */
3171 pkt_descr
= epp
->ep_isoc_info
.isoc_pkt_descr
;
3172 n_pkt
= epp
->ep_isoc_info
.isoc_pkts_count
;
3173 if ((n_pkt
== 0) || (pkt_descr
== NULL
)) {
3175 epp
->ep_lcmd_status
= USB_LC_STAT_ISOC_UNINITIALIZED
;
3181 /* For OUT endpoint, return pkts transfer status of last request */
3182 if (UGEN_XFER_DIR(epp
) != USB_EP_DIR_IN
) {
3183 if (bp
->b_bcount
< sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
) {
3184 rval
= USB_INVALID_REQUEST
;
3185 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3189 bcopy(epp
->ep_isoc_info
.isoc_pkt_descr
, bp
->b_un
.b_addr
,
3190 n_pkt
* sizeof (ugen_isoc_pkt_descr_t
));
3191 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
3193 return (USB_SUCCESS
);
3196 /* read length should be the sum of pkt descrs and data length */
3197 pkts_len
= epp
->ep_isoc_info
.isoc_pkts_length
;
3198 if (bp
->b_bcount
!= pkts_len
+ sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
) {
3199 rval
= USB_INVALID_REQUEST
;
3200 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3205 /* can we satisfy this read? */
3207 len
= min(MBLKL(epp
->ep_data
),
3210 * every msg block in ep_data must be the size of
3211 * pkts_len(payload length) + pkt descrs len
3213 ASSERT((len
== 0) || (len
== bp
->b_bcount
));
3217 * if polling not active, restart
3218 * if there is some data, return the data
3220 if ((epp
->ep_state
& UGEN_EP_STATE_ISOC_IN_POLLING_ON
) == 0) {
3223 if ((rval
= ugen_epx_isoc_IN_start_polling(ugenp
,
3224 epp
)) != USB_SUCCESS
) {
3225 epp
->ep_lcmd_status
=
3226 USB_LC_STAT_ISOC_POLLING_FAILED
;
3231 } else if (epp
->ep_data
&& (len
>= bp
->b_bcount
)) {
3232 bcopy(epp
->ep_data
->b_rptr
, bp
->b_un
.b_addr
,
3235 epp
->ep_data
->b_rptr
+= bp
->b_bcount
;
3242 * if there is data or FNDELAY, return available data
3244 if (epp
->ep_data
&& (len
>= bp
->b_bcount
)) {
3245 /* can fulfill this read request */
3246 bcopy(epp
->ep_data
->b_rptr
, bp
->b_un
.b_addr
, bp
->b_bcount
);
3247 epp
->ep_data
->b_rptr
+= bp
->b_bcount
;
3249 } else if (epp
->ep_xfer_oflag
& (FNDELAY
| FNONBLOCK
)) {
3250 bp
->b_resid
= bp
->b_bcount
;
3252 /* otherwise just wait for data */
3257 /* data have been read */
3258 if (epp
->ep_data
&& (epp
->ep_data
->b_rptr
== epp
->ep_data
->b_wptr
)) {
3261 /* remove the just read msg block */
3262 mp
= unlinkb(epp
->ep_data
);
3263 freemsg(epp
->ep_data
);
3268 epp
->ep_data
= NULL
;
3273 ASSERT(epp
->ep_state
& UGEN_EP_STATE_ISOC_IN_POLLING_ON
);
3276 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3277 "ugen_epx_isoc_IN_req end: rval=%d bcount=%lu len=%d data=0x%p",
3278 rval
, bp
->b_bcount
, len
, (void *)epp
->ep_data
);
3285 * Start polling on isoc endpoint, asynchronously
3288 ugen_epx_isoc_IN_start_polling(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
3290 int rval
= USB_FAILURE
;
3291 usb_isoc_req_t
*reqp
;
3292 ugen_isoc_pkt_descr_t
*pkt_descr
;
3293 ushort_t n_pkt
, pkt
;
3297 * if polling is being stopped, we restart polling in the
3298 * isoc callback again
3300 if (epp
->ep_state
& UGEN_EP_STATE_ISOC_IN_POLLING_IS_STOPPED
) {
3305 if ((epp
->ep_state
& UGEN_EP_STATE_ISOC_IN_POLLING_ON
) == 0) {
3306 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3307 "ugen_epx_isoc_IN_start_polling: epp=0x%p state=0x%x",
3308 (void *)epp
, epp
->ep_state
);
3310 pkts_len
= epp
->ep_isoc_info
.isoc_pkts_length
;
3311 n_pkt
= epp
->ep_isoc_info
.isoc_pkts_count
;
3312 pkt_descr
= epp
->ep_isoc_info
.isoc_pkt_descr
;
3314 epp
->ep_state
|= UGEN_EP_STATE_ISOC_IN_POLLING_ON
;
3315 mutex_exit(&epp
->ep_mutex
);
3317 if ((reqp
= usb_alloc_isoc_req(ugenp
->ug_dip
, n_pkt
, pkts_len
,
3318 USB_FLAGS_NOSLEEP
)) == NULL
) {
3319 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3320 "ugen_epx_isoc_IN_start_polling: alloc isoc "
3322 mutex_enter(&epp
->ep_mutex
);
3323 epp
->ep_state
&= ~UGEN_EP_STATE_ISOC_IN_POLLING_ON
;
3325 return (USB_NO_RESOURCES
);
3327 reqp
->isoc_client_private
= (usb_opaque_t
)ugenp
;
3329 reqp
->isoc_attributes
= USB_ATTRS_AUTOCLEARING
|
3330 USB_ATTRS_SHORT_XFER_OK
| USB_ATTRS_ISOC_XFER_ASAP
;
3333 * isoc_pkts_length was defined to be ushort_t. This
3334 * has been obsoleted by usb high speed isoc support.
3335 * It is set here just for compatibility reason
3337 reqp
->isoc_pkts_length
= 0;
3339 for (pkt
= 0; pkt
< n_pkt
; pkt
++) {
3340 reqp
->isoc_pkt_descr
[pkt
].isoc_pkt_length
=
3341 pkt_descr
[pkt
].dsc_isoc_pkt_len
;
3343 reqp
->isoc_pkts_count
= n_pkt
;
3344 reqp
->isoc_cb
= ugen_epx_isoc_IN_req_cb
;
3345 reqp
->isoc_exc_cb
= ugen_epx_isoc_IN_req_cb
;
3347 if ((rval
= usb_pipe_isoc_xfer(epp
->ep_ph
, reqp
,
3348 USB_FLAGS_NOSLEEP
)) != USB_SUCCESS
) {
3349 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3350 "ugen_epx_isoc_IN_start_polling: failed %d", rval
);
3351 usb_free_isoc_req(reqp
);
3354 mutex_enter(&epp
->ep_mutex
);
3355 if (rval
!= USB_SUCCESS
) {
3356 epp
->ep_state
&= ~UGEN_EP_STATE_ISOC_IN_POLLING_ON
;
3367 * stop polling on an isoc endpoint, asynchronously
3370 ugen_epx_isoc_IN_stop_polling(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
3372 if ((epp
->ep_state
& UGEN_EP_STATE_ISOC_IN_POLLING_ON
) &&
3373 ((epp
->ep_state
& UGEN_EP_STATE_ISOC_IN_POLLING_IS_STOPPED
) == 0)) {
3374 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3375 "ugen_epx_isoc_IN_stop_polling: epp=0x%p state=0x%x",
3376 (void *)epp
, epp
->ep_state
);
3378 epp
->ep_state
|= UGEN_EP_STATE_ISOC_IN_POLLING_IS_STOPPED
;
3379 mutex_exit(&epp
->ep_mutex
);
3380 usb_pipe_stop_isoc_polling(epp
->ep_ph
, USB_FLAGS_NOSLEEP
);
3381 mutex_enter(&epp
->ep_mutex
);
3390 ugen_epx_isoc_IN_poll_wakeup(ugen_state_t
*ugenp
, ugen_ep_t
*epp
)
3392 if (epp
->ep_state
& UGEN_EP_STATE_ISOC_IN_POLL_PENDING
) {
3393 struct pollhead
*phpp
= &epp
->ep_pollhead
;
3395 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3396 "ugen_epx_isoc_IN_poll_wakeup: state=0x%x", epp
->ep_state
);
3398 epp
->ep_state
&= ~UGEN_EP_STATE_ISOC_IN_POLL_PENDING
;
3399 mutex_exit(&epp
->ep_mutex
);
3400 pollwakeup(phpp
, POLLIN
);
3401 mutex_enter(&epp
->ep_mutex
);
3407 * callback functions for isoc IN pipe
3410 ugen_epx_isoc_IN_req_cb(usb_pipe_handle_t ph
, usb_isoc_req_t
*reqp
)
3412 ugen_state_t
*ugenp
= (ugen_state_t
*)reqp
->isoc_client_private
;
3413 ugen_ep_t
*epp
= (ugen_ep_t
*)usb_pipe_get_private(ph
);
3416 /* pipe is closing */
3421 ASSERT(!mutex_owned(&epp
->ep_mutex
)); /* not owned */
3423 mutex_enter(&epp
->ep_mutex
);
3425 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3426 "ugen_epx_isoc_IN_req_cb: "
3427 "epp=0x%p state=0x%x ph=0x%p reqp=0x%p cr=%d cb=0x%x len=%ld "
3428 "isoc error count=%d, pkt cnt=%d", (void *)epp
, epp
->ep_state
,
3429 (void *)ph
, (void *)reqp
, reqp
->isoc_completion_reason
,
3430 reqp
->isoc_cb_flags
, (reqp
->isoc_data
== NULL
) ? 0 :
3431 MBLKL(reqp
->isoc_data
),
3432 reqp
->isoc_error_count
, reqp
->isoc_pkts_count
);
3434 /* Too many packet errors during isoc transfer of this request */
3435 if (reqp
->isoc_error_count
== reqp
->isoc_pkts_count
) {
3436 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3437 "too many errors(%d) in this req, stop polling",
3438 reqp
->isoc_error_count
);
3439 epp
->ep_lcmd_status
= USB_LC_STAT_ISOC_PKT_ERROR
;
3440 ugen_epx_isoc_IN_stop_polling(ugenp
, epp
);
3444 if (reqp
->isoc_data
&& !reqp
->isoc_completion_reason
) {
3445 mblk_t
*mp1
= NULL
, *mp2
= NULL
;
3446 usb_isoc_pkt_descr_t
*pkt_descr
=
3447 reqp
->isoc_pkt_descr
;
3448 ushort_t i
, n_pkt
= reqp
->isoc_pkts_count
;
3450 for (i
= 0; i
< n_pkt
; i
++) {
3451 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3452 "pkt %d: len=%d status=%d actual_len=%d", i
,
3453 pkt_descr
[i
].isoc_pkt_length
,
3454 pkt_descr
[i
].isoc_pkt_status
,
3455 pkt_descr
[i
].isoc_pkt_actual_length
);
3457 /* translate cr to ugen lcstat */
3458 pkt_descr
[i
].isoc_pkt_status
=
3459 ugen_cr2lcstat(pkt_descr
[i
].isoc_pkt_status
);
3462 /* construct data buffer: pkt descriptors + payload */
3463 mp2
= allocb(sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
, BPRI_HI
);
3465 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3466 "alloc msgblk failed, discard data");
3468 /* pkt descrs first */
3469 bcopy(pkt_descr
, mp2
->b_wptr
,
3470 sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
);
3472 mp2
->b_wptr
+= sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
;
3474 /* payload follows */
3475 linkb(mp2
, reqp
->isoc_data
);
3477 /* concatenate data bytes in mp2 */
3478 if ((mp1
= msgpullup(mp2
, -1)) != NULL
) {
3480 * now we get the required data:
3481 * pkt descrs + payload
3483 reqp
->isoc_data
= NULL
;
3485 USB_DPRINTF_L2(UGEN_PRINT_XFER
,
3487 "msgpullup status blk failed, "
3496 if (epp
->ep_data
&& (mp1
!= NULL
)) {
3497 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3498 "ISOC ep%x coalesce ep_data",
3499 epp
->ep_descr
.bEndpointAddress
);
3501 /* add mp1 to the tail of ep_data */
3502 linkb(epp
->ep_data
, mp1
);
3504 } else if (mp1
!= NULL
) {
3505 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3511 switch (reqp
->isoc_completion_reason
) {
3513 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
3516 case USB_CR_PIPE_RESET
:
3517 case USB_CR_STOPPED_POLLING
:
3518 case USB_CR_PIPE_CLOSING
:
3522 epp
->ep_lcmd_status
=
3523 ugen_cr2lcstat(reqp
->isoc_completion_reason
);
3524 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3525 "ugen_exp_isoc_cb_req: error lcmd_status=0x%x ",
3526 epp
->ep_lcmd_status
);
3531 /* any non-zero completion reason signifies polling has stopped */
3532 if (reqp
->isoc_completion_reason
) {
3533 epp
->ep_state
&= ~(UGEN_EP_STATE_ISOC_IN_POLLING_ON
|
3534 UGEN_EP_STATE_ISOC_IN_POLLING_IS_STOPPED
);
3538 /* is there a poll pending? should we stop polling? */
3540 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3541 "ugen_epx_isoc_IN_req_cb: data len=0x%lx, limit=0x%lx",
3542 msgdsize(epp
->ep_data
),
3545 ugen_epx_isoc_IN_poll_wakeup(ugenp
, epp
);
3549 * Since isoc is unreliable xfer, if buffered data size exceeds
3550 * the limit, we just discard and free data in the oldest mblk
3553 (msgdsize(epp
->ep_data
) >= epp
->ep_buf_limit
)) {
3556 /* exceed buf lenth limit, remove the oldest one */
3557 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3558 "ugen_epx_isoc_IN_req_cb: overflow!");
3559 mp
= unlinkb(epp
->ep_data
);
3561 freeb(epp
->ep_data
);
3568 if (reqp
->isoc_completion_reason
&& epp
->ep_bp
) {
3569 bioerror(epp
->ep_bp
, EIO
);
3571 cv_signal(&epp
->ep_wait_cv
);
3573 } else if (epp
->ep_data
&& epp
->ep_bp
&& !epp
->ep_done
) {
3576 /* can we satisfy the read now */
3577 if ((ugen_epx_isoc_IN_req(ugenp
, epp
, epp
->ep_bp
, &wait
) ==
3578 USB_SUCCESS
) && (wait
== B_FALSE
)) {
3580 cv_signal(&epp
->ep_wait_cv
);
3583 mutex_exit(&epp
->ep_mutex
);
3587 usb_free_isoc_req(reqp
);
3591 * handle isoc OUT xfers or init isoc IN polling
3594 ugen_epx_isoc_OUT_req(ugen_state_t
*ugenp
, ugen_ep_t
*epp
,
3595 struct buf
*bp
, boolean_t
*wait
)
3597 int rval
= USB_SUCCESS
;
3598 usb_isoc_req_t
*reqp
;
3599 ugen_isoc_pkt_descr_t
*pkt_descr
;
3600 ushort_t pkt
, n_pkt
= 0;
3601 uint_t pkts_len
= 0;
3604 ugen_isoc_req_head_t
*pkth
;
3606 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3607 "ugen_epx_isoc_OUT_req: epp=0x%p state=0x%x bp=0x%p",
3608 (void *)epp
, epp
->ep_state
, (void *)bp
);
3612 if (bp
->b_bcount
< sizeof (int)) {
3613 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3614 rval
= USB_INVALID_REQUEST
;
3619 /* LINTED E_BAD_PTR_CAST_ALIGN */
3620 pkth
= (ugen_isoc_req_head_t
*)bp
->b_un
.b_addr
;
3621 n_pkt
= pkth
->req_isoc_pkts_count
;
3622 head_len
= sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
+
3626 (n_pkt
> usb_get_max_pkts_per_isoc_request(ugenp
->ug_dip
)) ||
3627 (bp
->b_bcount
< head_len
)) {
3628 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3629 "Invalid params: bcount=%lu, head_len=%d, pktcnt=%d",
3630 bp
->b_bcount
, head_len
, n_pkt
);
3632 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3633 rval
= USB_INVALID_REQUEST
;
3638 p
= bp
->b_un
.b_addr
;
3639 p
+= sizeof (int); /* points to pkt_descrs */
3641 pkt_descr
= kmem_zalloc(sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
,
3643 if (pkt_descr
== NULL
) {
3644 epp
->ep_lcmd_status
= USB_LC_STAT_NO_RESOURCES
;
3645 rval
= USB_NO_RESOURCES
;
3649 bcopy(p
, pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
);
3650 p
+= sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
;
3652 /* total packet payload length */
3653 for (pkt
= 0; pkt
< n_pkt
; pkt
++) {
3654 pkts_len
+= pkt_descr
[pkt
].dsc_isoc_pkt_len
;
3658 * write length may either be header length for isoc IN endpoint or
3659 * the sum of header and data pkts length for isoc OUT endpoint
3661 if (((bp
->b_bcount
!= head_len
) &&
3662 (bp
->b_bcount
!= head_len
+ pkts_len
))) {
3663 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3664 "invalid length: bcount=%lu, head_len=%d, pkts_len = %d,"
3665 "pktcnt=%d", bp
->b_bcount
, head_len
, pkts_len
, n_pkt
);
3667 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3668 kmem_free(pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
);
3669 rval
= USB_INVALID_REQUEST
;
3675 ASSERT(epp
->ep_state
& UGEN_EP_STATE_XS_OPEN
);
3677 /* Set parameters for READ */
3678 if (bp
->b_bcount
== head_len
) {
3679 /* must be isoc IN endpoint */
3680 if ((UGEN_XFER_DIR(epp
) & USB_EP_DIR_IN
) == 0) {
3681 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3682 kmem_free(pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) *
3684 rval
= USB_INVALID_REQUEST
;
3685 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3686 "write length invalid for OUT ep%x",
3687 epp
->ep_descr
.bEndpointAddress
);
3692 if (epp
->ep_isoc_in_inited
) {
3693 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3694 kmem_free(pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) *
3696 rval
= USB_INVALID_REQUEST
;
3697 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3698 "isoc IN polling fail: already inited, need to"
3699 "close the ep before initing again");
3704 /* save pkts info for the READ */
3705 epp
->ep_isoc_info
.isoc_pkts_count
= n_pkt
;
3706 epp
->ep_isoc_info
.isoc_pkts_length
= pkts_len
;
3707 epp
->ep_isoc_info
.isoc_pkt_descr
= pkt_descr
;
3709 if ((rval
= ugen_epx_isoc_IN_start_polling(ugenp
,
3710 epp
)) != USB_SUCCESS
) {
3711 epp
->ep_lcmd_status
=
3712 USB_LC_STAT_ISOC_POLLING_FAILED
;
3713 kmem_free(pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) *
3715 epp
->ep_isoc_info
.isoc_pkts_count
= 0;
3716 epp
->ep_isoc_info
.isoc_pkts_length
= 0;
3717 epp
->ep_isoc_info
.isoc_pkt_descr
= NULL
;
3719 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3720 "isoc IN start polling failed");
3725 epp
->ep_bp
->b_resid
= epp
->ep_bp
->b_bcount
- head_len
;
3727 epp
->ep_isoc_in_inited
++;
3728 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3729 "isoc IN ep inited");
3734 /* must be isoc OUT endpoint */
3735 if (UGEN_XFER_DIR(epp
) & USB_EP_DIR_IN
) {
3736 epp
->ep_lcmd_status
= USB_LC_STAT_INVALID_REQ
;
3737 kmem_free(pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
);
3738 rval
= USB_INVALID_REQUEST
;
3739 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3740 "write length invalid for an IN ep%x",
3741 epp
->ep_descr
.bEndpointAddress
);
3746 /* OUT endpoint, free previous info if there's any */
3747 if (epp
->ep_isoc_info
.isoc_pkt_descr
) {
3748 kmem_free(epp
->ep_isoc_info
.isoc_pkt_descr
,
3749 sizeof (ugen_isoc_pkt_descr_t
) *
3750 epp
->ep_isoc_info
.isoc_pkts_count
);
3753 /* save pkts info for the WRITE */
3754 epp
->ep_isoc_info
.isoc_pkts_count
= n_pkt
;
3755 epp
->ep_isoc_info
.isoc_pkts_length
= pkts_len
;
3756 epp
->ep_isoc_info
.isoc_pkt_descr
= pkt_descr
;
3758 reqp
= usb_alloc_isoc_req(ugenp
->ug_dip
, n_pkt
, pkts_len
,
3761 epp
->ep_lcmd_status
= USB_LC_STAT_NO_RESOURCES
;
3762 kmem_free(pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
);
3763 rval
= USB_NO_RESOURCES
;
3764 epp
->ep_isoc_info
.isoc_pkts_count
= 0;
3765 epp
->ep_isoc_info
.isoc_pkts_length
= 0;
3766 epp
->ep_isoc_info
.isoc_pkt_descr
= NULL
;
3768 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3769 "alloc isoc out req failed");
3773 for (pkt
= 0; pkt
< n_pkt
; pkt
++) {
3774 reqp
->isoc_pkt_descr
[pkt
].isoc_pkt_length
=
3775 pkt_descr
[pkt
].dsc_isoc_pkt_len
;
3777 reqp
->isoc_pkts_count
= n_pkt
;
3778 reqp
->isoc_client_private
= (usb_opaque_t
)ugenp
;
3779 reqp
->isoc_attributes
= USB_ATTRS_AUTOCLEARING
|
3780 USB_ATTRS_ISOC_XFER_ASAP
;
3782 reqp
->isoc_cb
= ugen_epx_isoc_OUT_req_cb
;
3783 reqp
->isoc_exc_cb
= ugen_epx_isoc_OUT_req_cb
;
3785 /* copy data from bp */
3786 bcopy(p
, reqp
->isoc_data
->b_wptr
, pkts_len
);
3787 reqp
->isoc_data
->b_wptr
+= pkts_len
;
3789 mutex_exit(&epp
->ep_mutex
);
3790 if ((rval
= usb_pipe_isoc_xfer(epp
->ep_ph
, reqp
,
3791 USB_FLAGS_NOSLEEP
)) != USB_SUCCESS
) {
3792 mutex_enter(&epp
->ep_mutex
);
3793 epp
->ep_lcmd_status
=
3794 ugen_cr2lcstat(reqp
->isoc_completion_reason
);
3795 usb_free_isoc_req(reqp
);
3796 kmem_free(pkt_descr
, sizeof (ugen_isoc_pkt_descr_t
) * n_pkt
);
3798 epp
->ep_isoc_info
.isoc_pkt_descr
= NULL
;
3799 epp
->ep_isoc_info
.isoc_pkts_count
= 0;
3800 epp
->ep_isoc_info
.isoc_pkts_length
= 0;
3802 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3803 "isoc out xfer failed");
3807 mutex_enter(&epp
->ep_mutex
);
3809 *wait
= (rval
== USB_SUCCESS
) ? B_TRUE
: B_FALSE
;
3812 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3813 "ugen_epx_isoc_OUT_req end: rval=%d bcount=%lu xfer_len=%d",
3814 rval
, bp
->b_bcount
, pkts_len
);
3821 * callback functions for isoc OUT pipe
3824 ugen_epx_isoc_OUT_req_cb(usb_pipe_handle_t ph
, usb_isoc_req_t
*reqp
)
3826 ugen_state_t
*ugenp
= (ugen_state_t
*)reqp
->isoc_client_private
;
3827 ugen_ep_t
*epp
= (ugen_ep_t
*)usb_pipe_get_private(ph
);
3829 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3830 "ugen_epx_isoc_OUT_req_cb: ph=0x%p reqp=0x%p cr=%d cb=0x%x",
3831 (void *)ph
, (void *)reqp
, reqp
->isoc_completion_reason
,
3832 reqp
->isoc_cb_flags
);
3834 /* epp might be NULL if we are closing the pipe */
3836 ugen_isoc_pkt_info_t info
;
3838 mutex_enter(&epp
->ep_mutex
);
3840 info
= epp
->ep_isoc_info
;
3844 usb_isoc_pkt_descr_t
*pktdesc
;
3846 pktdesc
= reqp
->isoc_pkt_descr
;
3847 headlen
= info
.isoc_pkts_count
*
3848 sizeof (ugen_isoc_pkt_descr_t
);
3850 len
= min(headlen
+ MBLKL(reqp
->isoc_data
),
3851 epp
->ep_bp
->b_bcount
);
3853 epp
->ep_bp
->b_resid
= epp
->ep_bp
->b_bcount
- len
;
3856 switch (reqp
->isoc_completion_reason
) {
3859 epp
->ep_lcmd_status
= USB_LC_STAT_NOERROR
;
3861 for (i
= 0; i
< reqp
->isoc_pkts_count
; i
++) {
3862 pktdesc
[i
].isoc_pkt_status
=
3863 ugen_cr2lcstat(pktdesc
[i
].
3867 /* save the status info */
3868 bcopy(reqp
->isoc_pkt_descr
,
3869 info
.isoc_pkt_descr
,
3870 (sizeof (ugen_isoc_pkt_descr_t
) *
3871 info
.isoc_pkts_count
));
3874 case USB_CR_PIPE_RESET
:
3878 epp
->ep_lcmd_status
=
3880 reqp
->isoc_completion_reason
);
3881 bioerror(epp
->ep_bp
, EIO
);
3885 cv_signal(&epp
->ep_wait_cv
);
3886 mutex_exit(&epp
->ep_mutex
);
3889 usb_free_isoc_req(reqp
);
3894 * Endpoint status node management
3896 * open/close an endpoint status node.
3898 * Return values: errno
3901 ugen_eps_open(ugen_state_t
*ugenp
, dev_t dev
, int flag
)
3903 ugen_ep_t
*epp
= &ugenp
->ug_ep
[UGEN_MINOR_EPIDX(ugenp
, dev
)];
3906 mutex_enter(&epp
->ep_mutex
);
3907 USB_DPRINTF_L4(UGEN_PRINT_STAT
, ugenp
->ug_log_hdl
,
3908 "ugen_eps_open: dev=0x%lx flag=0x%x state=0x%x",
3909 dev
, flag
, epp
->ep_state
);
3911 ASSERT(epp
->ep_state
& UGEN_EP_STATE_ACTIVE
);
3913 /* only one open at the time */
3914 if ((epp
->ep_state
& UGEN_EP_STATE_STAT_OPEN
) == 0) {
3915 epp
->ep_state
|= UGEN_EP_STATE_STAT_OPEN
;
3916 epp
->ep_stat_oflag
= flag
;
3919 mutex_exit(&epp
->ep_mutex
);
3926 * close endpoint status
3929 ugen_eps_close(ugen_state_t
*ugenp
, dev_t dev
, int flag
)
3931 ugen_ep_t
*epp
= &ugenp
->ug_ep
[UGEN_MINOR_EPIDX(ugenp
, dev
)];
3933 mutex_enter(&epp
->ep_mutex
);
3934 USB_DPRINTF_L4(UGEN_PRINT_STAT
, ugenp
->ug_log_hdl
,
3935 "ugen_eps_close: dev=0x%lx flag=0x%x state=0x%x",
3936 dev
, flag
, epp
->ep_state
);
3938 epp
->ep_state
&= ~(UGEN_EP_STATE_STAT_OPEN
|
3939 UGEN_EP_STATE_INTR_IN_POLL_PENDING
|
3940 UGEN_EP_STATE_ISOC_IN_POLL_PENDING
);
3941 epp
->ep_one_xfer
= B_FALSE
;
3943 USB_DPRINTF_L4(UGEN_PRINT_STAT
, ugenp
->ug_log_hdl
,
3944 "ugen_eps_close: state=0x%x", epp
->ep_state
);
3946 ASSERT(epp
->ep_state
& UGEN_EP_STATE_ACTIVE
);
3947 mutex_exit(&epp
->ep_mutex
);
3952 * return status info
3954 * Return values: errno
3957 ugen_eps_req(ugen_state_t
*ugenp
, struct buf
*bp
)
3959 ugen_ep_t
*epp
= &ugenp
->ug_ep
[UGEN_MINOR_EPIDX(ugenp
, bp
->b_edev
)];
3961 mutex_enter(&epp
->ep_mutex
);
3962 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3963 "ugen_eps_req: bp=0x%p lcmd_status=0x%x bcount=%lu",
3964 (void *)bp
, epp
->ep_lcmd_status
, bp
->b_bcount
);
3966 if (bp
->b_flags
& B_READ
) {
3967 int len
= min(sizeof (epp
->ep_lcmd_status
), bp
->b_bcount
);
3969 bcopy(&epp
->ep_lcmd_status
, bp
->b_un
.b_addr
, len
);
3971 bp
->b_resid
= bp
->b_bcount
- len
;
3973 USB_DPRINTF_L3(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3974 "ugen_eps_req: control=0x%x",
3975 *((char *)(bp
->b_un
.b_addr
)));
3977 if (epp
->ep_state
& UGEN_EP_STATE_XFER_OPEN
) {
3978 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3979 "ugen_eps_req: cannot change one xfer mode if "
3980 "endpoint is open");
3982 mutex_exit(&epp
->ep_mutex
);
3987 if ((epp
->ep_descr
.bmAttributes
& USB_EP_ATTR_INTR
) &&
3988 (epp
->ep_descr
.bEndpointAddress
& USB_EP_DIR_IN
)) {
3989 epp
->ep_one_xfer
= (*((char *)(bp
->b_un
.b_addr
)) &
3990 USB_EP_INTR_ONE_XFER
) ? B_TRUE
: B_FALSE
;
3992 USB_DPRINTF_L2(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
3993 "ugen_eps_req: not an interrupt endpoint");
3995 mutex_exit(&epp
->ep_mutex
);
4000 bp
->b_resid
= bp
->b_bcount
- 1;
4002 mutex_exit(&epp
->ep_mutex
);
4009 * device status node management
4012 ugen_ds_init(ugen_state_t
*ugenp
)
4014 cv_init(&ugenp
->ug_ds
.dev_wait_cv
, NULL
, CV_DRIVER
, NULL
);
4016 /* Create devstat minor node for this instance */
4017 if (ugen_ds_minor_nodes_create(ugenp
) != USB_SUCCESS
) {
4018 USB_DPRINTF_L2(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
4019 "ugen_create_dev_stat_minor_nodes failed");
4021 return (USB_FAILURE
);
4025 return (USB_SUCCESS
);
4030 ugen_ds_destroy(ugen_state_t
*ugenp
)
4032 cv_destroy(&ugenp
->ug_ds
.dev_wait_cv
);
4037 * open devstat minor node
4039 * Return values: errno
4042 ugen_ds_open(ugen_state_t
*ugenp
, dev_t dev
, int flag
)
4044 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
4045 "ugen_ds_open: dev=0x%lx flag=0x%x", dev
, flag
);
4047 mutex_enter(&ugenp
->ug_mutex
);
4048 if ((ugenp
->ug_ds
.dev_stat
& UGEN_DEV_STATUS_ACTIVE
) == 0) {
4050 * first read on device node should return status
4052 ugenp
->ug_ds
.dev_stat
|= UGEN_DEV_STATUS_CHANGED
|
4053 UGEN_DEV_STATUS_ACTIVE
;
4054 ugenp
->ug_ds
.dev_oflag
= flag
;
4055 mutex_exit(&ugenp
->ug_mutex
);
4059 mutex_exit(&ugenp
->ug_mutex
);
4067 ugen_ds_close(ugen_state_t
*ugenp
, dev_t dev
, int flag
)
4069 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
4070 "ugen_ds_close: dev=0x%lx flag=0x%x", dev
, flag
);
4072 mutex_enter(&ugenp
->ug_mutex
);
4073 ugenp
->ug_ds
.dev_stat
= UGEN_DEV_STATUS_INACTIVE
;
4074 mutex_exit(&ugenp
->ug_mutex
);
4079 * request for devstat
4081 * Return values: errno
4084 ugen_ds_req(ugen_state_t
*ugenp
, struct buf
*bp
)
4086 int len
= min(sizeof (ugenp
->ug_ds
.dev_state
), bp
->b_bcount
);
4088 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
4089 "ugen_ds_req: bp=0x%p", (void *)bp
);
4091 mutex_enter(&ugenp
->ug_mutex
);
4092 if ((ugenp
->ug_ds
.dev_oflag
& (FNDELAY
| FNONBLOCK
)) == 0) {
4093 while ((ugenp
->ug_ds
.dev_stat
&
4094 UGEN_DEV_STATUS_CHANGED
) == 0) {
4095 if (cv_wait_sig(&ugenp
->ug_ds
.dev_wait_cv
,
4096 &ugenp
->ug_mutex
) <= 0) {
4097 mutex_exit(&ugenp
->ug_mutex
);
4102 } else if ((ugenp
->ug_ds
.dev_stat
& UGEN_DEV_STATUS_CHANGED
) ==
4104 bp
->b_resid
= bp
->b_bcount
;
4105 mutex_exit(&ugenp
->ug_mutex
);
4110 ugenp
->ug_ds
.dev_stat
&= ~UGEN_DEV_STATUS_CHANGED
;
4111 switch (ugenp
->ug_dev_state
) {
4112 case USB_DEV_ONLINE
:
4113 ugenp
->ug_ds
.dev_state
= USB_DEV_STAT_ONLINE
;
4116 case USB_DEV_DISCONNECTED
:
4117 ugenp
->ug_ds
.dev_state
= USB_DEV_STAT_DISCONNECTED
;
4120 case USB_DEV_SUSPENDED
:
4121 case USB_UGEN_DEV_UNAVAILABLE_RESUME
:
4122 ugenp
->ug_ds
.dev_state
= USB_DEV_STAT_RESUMED
;
4125 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT
:
4127 ugenp
->ug_ds
.dev_state
= USB_DEV_STAT_UNAVAILABLE
;
4132 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
4133 "ugen_ds_req: dev_state=0x%x dev_stat=0x%x",
4134 ugenp
->ug_dev_state
, ugenp
->ug_ds
.dev_stat
);
4136 bcopy(&ugenp
->ug_ds
.dev_state
, bp
->b_un
.b_addr
, len
);
4137 bp
->b_resid
= bp
->b_bcount
- len
;
4139 mutex_exit(&ugenp
->ug_mutex
);
4146 ugen_ds_change(ugen_state_t
*ugenp
)
4148 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
4151 ugenp
->ug_ds
.dev_stat
|= UGEN_DEV_STATUS_CHANGED
;
4152 cv_signal(&ugenp
->ug_ds
.dev_wait_cv
);
4160 ugen_ds_poll_wakeup(ugen_state_t
*ugenp
)
4162 USB_DPRINTF_L4(UGEN_PRINT_XFER
, ugenp
->ug_log_hdl
,
4163 "ugen_ds_poll_wakeup:");
4165 if (ugenp
->ug_ds
.dev_stat
& UGEN_DEV_STATUS_POLL_PENDING
) {
4166 struct pollhead
*phpp
= &ugenp
->ug_ds
.dev_pollhead
;
4167 ugenp
->ug_ds
.dev_stat
&= ~UGEN_DEV_STATUS_POLL_PENDING
;
4168 mutex_exit(&ugenp
->ug_mutex
);
4169 pollwakeup(phpp
, POLLIN
);
4170 mutex_enter(&ugenp
->ug_mutex
);
4176 * minor node management:
4179 ugen_ds_minor_nodes_create(ugen_state_t
*ugenp
)
4182 int vid
= ugenp
->ug_dev_data
->dev_descr
->idVendor
;
4183 int pid
= ugenp
->ug_dev_data
->dev_descr
->idProduct
;
4186 int owns_device
= (usb_owns_device(ugenp
->ug_dip
) ?
4187 UGEN_OWNS_DEVICE
: 0);
4189 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
4190 "ugen_ds_minor_nodes_create: idx shift=%d inst shift=%d",
4191 UGEN_MINOR_IDX_SHIFT(ugenp
),
4192 UGEN_MINOR_INSTANCE_SHIFT(ugenp
));
4194 if (ugenp
->ug_instance
>= UGEN_MINOR_INSTANCE_LIMIT(ugenp
)) {
4195 USB_DPRINTF_L0(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
4196 "instance number too high (%d)", ugenp
->ug_instance
);
4198 return (USB_FAILURE
);
4201 /* create devstat minor node */
4203 (void) sprintf(node_name
, "%x.%x.devstat", vid
, pid
);
4205 (void) sprintf(node_name
, "%x.%x.if%ddevstat", vid
, pid
,
4206 ugenp
->ug_dev_data
->dev_curr_if
);
4209 minor_index
= ugen_minor_index_create(ugenp
,
4210 (UGEN_MINOR_DEV_STAT_NODE
| owns_device
) <<
4211 UGEN_MINOR_IDX_SHIFT(ugenp
));
4213 if (minor_index
< 0) {
4214 USB_DPRINTF_L0(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
4215 "too many minor nodes");
4217 return (USB_FAILURE
);
4219 minor
= (minor_index
<< UGEN_MINOR_IDX_SHIFT(ugenp
)) |
4220 ugenp
->ug_instance
<< UGEN_MINOR_INSTANCE_SHIFT(ugenp
);
4222 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
4223 "minor=0x%x minor_index=%d name=%s",
4224 minor
, minor_index
, node_name
);
4226 ASSERT(minor
< L_MAXMIN
);
4228 if ((ddi_create_minor_node(ugenp
->ug_dip
, node_name
,
4229 S_IFCHR
, minor
, DDI_NT_UGEN
, 0)) != DDI_SUCCESS
) {
4231 return (USB_FAILURE
);
4234 ugen_store_devt(ugenp
, minor
);
4236 return (USB_SUCCESS
);
4241 * utility functions:
4243 * conversion from completion reason to USB_LC_STAT_*
4245 static struct ugen_cr2lcstat_entry
{
4248 } ugen_cr2lcstat_table
[] = {
4249 { USB_CR_OK
, USB_LC_STAT_NOERROR
},
4250 { USB_CR_CRC
, USB_LC_STAT_CRC
},
4251 { USB_CR_BITSTUFFING
, USB_LC_STAT_BITSTUFFING
},
4252 { USB_CR_DATA_TOGGLE_MM
, USB_LC_STAT_DATA_TOGGLE_MM
},
4253 { USB_CR_STALL
, USB_LC_STAT_STALL
},
4254 { USB_CR_DEV_NOT_RESP
, USB_LC_STAT_DEV_NOT_RESP
},
4255 { USB_CR_PID_CHECKFAILURE
, USB_LC_STAT_PID_CHECKFAILURE
},
4256 { USB_CR_UNEXP_PID
, USB_LC_STAT_UNEXP_PID
},
4257 { USB_CR_DATA_OVERRUN
, USB_LC_STAT_DATA_OVERRUN
},
4258 { USB_CR_DATA_UNDERRUN
, USB_LC_STAT_DATA_UNDERRUN
},
4259 { USB_CR_BUFFER_OVERRUN
, USB_LC_STAT_BUFFER_OVERRUN
},
4260 { USB_CR_BUFFER_UNDERRUN
, USB_LC_STAT_BUFFER_UNDERRUN
},
4261 { USB_CR_TIMEOUT
, USB_LC_STAT_TIMEOUT
},
4262 { USB_CR_NOT_ACCESSED
, USB_LC_STAT_NOT_ACCESSED
},
4263 { USB_CR_NO_RESOURCES
, USB_LC_STAT_NO_BANDWIDTH
},
4264 { USB_CR_UNSPECIFIED_ERR
, USB_LC_STAT_UNSPECIFIED_ERR
},
4265 { USB_CR_STOPPED_POLLING
, USB_LC_STAT_HW_ERR
},
4266 { USB_CR_PIPE_CLOSING
, USB_LC_STAT_UNSPECIFIED_ERR
},
4267 { USB_CR_PIPE_RESET
, USB_LC_STAT_UNSPECIFIED_ERR
},
4268 { USB_CR_NOT_SUPPORTED
, USB_LC_STAT_UNSPECIFIED_ERR
},
4269 { USB_CR_FLUSHED
, USB_LC_STAT_UNSPECIFIED_ERR
}
4272 #define UGEN_CR2LCSTAT_TABLE_SIZE (sizeof (ugen_cr2lcstat_table) / \
4273 sizeof (struct ugen_cr2lcstat_entry))
4275 ugen_cr2lcstat(int cr
)
4279 for (i
= 0; i
< UGEN_CR2LCSTAT_TABLE_SIZE
; i
++) {
4280 if (ugen_cr2lcstat_table
[i
].cr
== cr
) {
4282 return (ugen_cr2lcstat_table
[i
].lcstat
);
4286 return (USB_LC_STAT_UNSPECIFIED_ERR
);
4291 * create and lookup minor index
4294 ugen_minor_index_create(ugen_state_t
*ugenp
, ugen_minor_t minor
)
4298 /* check if already in the table */
4299 for (i
= 1; i
< ugenp
->ug_minor_node_table_index
; i
++) {
4300 if (ugenp
->ug_minor_node_table
[i
] == minor
) {
4305 if (ugenp
->ug_minor_node_table_index
<
4306 (ugenp
->ug_minor_node_table_size
/sizeof (ugen_minor_t
))) {
4307 ugenp
->ug_minor_node_table
[ugenp
->
4308 ug_minor_node_table_index
] = minor
;
4310 USB_DPRINTF_L4(UGEN_PRINT_ATTA
, ugenp
->ug_log_hdl
,
4311 "ugen_minor_index_create: %d: 0x%lx",
4312 ugenp
->ug_minor_node_table_index
,
4313 (unsigned long)minor
);
4315 return (ugenp
->ug_minor_node_table_index
++);
4324 ugen_devt2minor(ugen_state_t
*ugenp
, dev_t dev
)
4326 USB_DPRINTF_L4(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
4327 "ugen_devt2minor: minorindex=%lu, minor=0x%" PRIx64
,
4328 UGEN_MINOR_GET_IDX(ugenp
, dev
),
4329 ugenp
->ug_minor_node_table
[UGEN_MINOR_GET_IDX(ugenp
, dev
)]);
4331 ASSERT(UGEN_MINOR_GET_IDX(ugenp
, dev
) <
4332 ugenp
->ug_minor_node_table_index
);
4334 return (ugenp
->ug_minor_node_table
[UGEN_MINOR_GET_IDX(ugenp
, dev
)]);
4339 ugen_is_valid_minor_node(ugen_state_t
*ugenp
, dev_t dev
)
4341 int idx
= UGEN_MINOR_GET_IDX(ugenp
, dev
);
4343 if ((idx
< ugenp
->ug_minor_node_table_index
) &&
4346 return (USB_SUCCESS
);
4348 USB_DPRINTF_L2(UGEN_PRINT_CBOPS
, ugenp
->ug_log_hdl
,
4349 "ugen_is_valid_minor_node: invalid minorindex=%d", idx
);
4351 return (USB_FAILURE
);
4356 ugen_minor_node_table_create(ugen_state_t
*ugenp
)
4358 size_t size
= sizeof (ugen_minor_t
) * UGEN_MINOR_IDX_LIMIT(ugenp
);
4360 /* allocate the max table size needed, we reduce later */
4361 ugenp
->ug_minor_node_table
= kmem_zalloc(size
, KM_SLEEP
);
4362 ugenp
->ug_minor_node_table_size
= size
;
4363 ugenp
->ug_minor_node_table_index
= 1;
4368 ugen_minor_node_table_shrink(ugen_state_t
*ugenp
)
4370 /* reduce the table size to save some memory */
4371 if (ugenp
->ug_minor_node_table_index
< UGEN_MINOR_IDX_LIMIT(ugenp
)) {
4372 size_t newsize
= sizeof (ugen_minor_t
) *
4373 ugenp
->ug_minor_node_table_index
;
4374 ugen_minor_t
*buf
= kmem_zalloc(newsize
, KM_SLEEP
);
4376 bcopy(ugenp
->ug_minor_node_table
, buf
, newsize
);
4377 kmem_free(ugenp
->ug_minor_node_table
,
4378 ugenp
->ug_minor_node_table_size
);
4379 ugenp
->ug_minor_node_table
= buf
;
4380 ugenp
->ug_minor_node_table_size
= newsize
;
4386 ugen_minor_node_table_destroy(ugen_state_t
*ugenp
)
4388 if (ugenp
->ug_minor_node_table
) {
4389 kmem_free(ugenp
->ug_minor_node_table
,
4390 ugenp
->ug_minor_node_table_size
);
4396 ugen_check_mask(uint_t mask
, uint_t
*shift
, uint_t
*limit
)
4400 for (i
= 0; i
< UGEN_MINOR_NODE_SIZE
; i
++) {
4401 if ((1 << i
) & mask
) {
4407 for (j
= i
; j
< UGEN_MINOR_NODE_SIZE
; j
++) {
4408 if (((1 << j
) & mask
) == 0) {
4414 *limit
= (i
== j
) ? 0 : 1 << (j
- i
);
4424 * Initialize power management and remote wakeup functionality.
4425 * No mutex is necessary in this function as it's called only by attach.
4428 ugen_pm_init(ugen_state_t
*ugenp
)
4430 dev_info_t
*dip
= ugenp
->ug_dip
;
4431 ugen_power_t
*ugenpm
;
4433 USB_DPRINTF_L4(UGEN_PRINT_PM
, ugenp
->ug_log_hdl
,
4436 /* Allocate the state structure */
4437 ugenpm
= kmem_zalloc(sizeof (ugen_power_t
), KM_SLEEP
);
4439 mutex_enter(&ugenp
->ug_mutex
);
4440 ugenp
->ug_pm
= ugenpm
;
4441 ugenpm
->pwr_wakeup_enabled
= B_FALSE
;
4442 ugenpm
->pwr_current
= USB_DEV_OS_FULL_PWR
;
4443 mutex_exit(&ugenp
->ug_mutex
);
4446 * If remote wakeup is not available you may not want to do
4449 if (ugen_enable_pm
|| usb_handle_remote_wakeup(dip
,
4450 USB_REMOTE_WAKEUP_ENABLE
) == USB_SUCCESS
) {
4451 if (usb_create_pm_components(dip
,
4452 &ugenpm
->pwr_states
) == USB_SUCCESS
) {
4453 USB_DPRINTF_L4(UGEN_PRINT_PM
,
4456 "created PM components");
4458 mutex_enter(&ugenp
->ug_mutex
);
4459 ugenpm
->pwr_wakeup_enabled
= B_TRUE
;
4460 mutex_exit(&ugenp
->ug_mutex
);
4462 if (pm_raise_power(dip
, 0,
4463 USB_DEV_OS_FULL_PWR
) != DDI_SUCCESS
) {
4464 USB_DPRINTF_L2(UGEN_PRINT_PM
,
4467 "raising power failed");
4470 USB_DPRINTF_L2(UGEN_PRINT_PM
,
4473 "create_pm_comps failed");
4476 USB_DPRINTF_L2(UGEN_PRINT_PM
,
4477 ugenp
->ug_log_hdl
, "ugen_pm_init: "
4478 "failure enabling remote wakeup");
4481 USB_DPRINTF_L4(UGEN_PRINT_PM
, ugenp
->ug_log_hdl
,
4482 "ugen_pm_init: end");
4488 * Shut down and destroy power management and remote wakeup functionality.
4491 ugen_pm_destroy(ugen_state_t
*ugenp
)
4493 dev_info_t
*dip
= ugenp
->ug_dip
;
4495 USB_DPRINTF_L4(UGEN_PRINT_PM
, ugenp
->ug_log_hdl
,
4496 "ugen_pm_destroy:");
4499 mutex_exit(&ugenp
->ug_mutex
);
4500 ugen_pm_busy_component(ugenp
);
4501 mutex_enter(&ugenp
->ug_mutex
);
4503 if ((ugenp
->ug_pm
->pwr_wakeup_enabled
) &&
4504 (ugenp
->ug_dev_state
!= USB_DEV_DISCONNECTED
)) {
4507 mutex_exit(&ugenp
->ug_mutex
);
4508 (void) pm_raise_power(dip
, 0, USB_DEV_OS_FULL_PWR
);
4510 if ((rval
= usb_handle_remote_wakeup(dip
,
4511 USB_REMOTE_WAKEUP_DISABLE
)) != USB_SUCCESS
) {
4512 USB_DPRINTF_L4(UGEN_PRINT_PM
,
4513 ugenp
->ug_log_hdl
, "ugen_pm_destroy: "
4514 "disabling rmt wakeup: rval=%d", rval
);
4517 * Since remote wakeup is disabled now,
4518 * no one can raise power
4519 * and get to device once power is lowered here.
4522 mutex_exit(&ugenp
->ug_mutex
);
4524 (void) pm_lower_power(dip
, 0, USB_DEV_OS_PWR_OFF
);
4525 ugen_pm_idle_component(ugenp
);
4527 mutex_enter(&ugenp
->ug_mutex
);
4528 kmem_free(ugenp
->ug_pm
, sizeof (ugen_power_t
));
4529 ugenp
->ug_pm
= NULL
;
4536 * Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
4537 * usb_req_raise_power and usb_req_lower_power.
4541 usb_ugen_power(usb_ugen_hdl_t usb_ugen_hdl
, int comp
, int level
)
4544 int rval
= USB_FAILURE
;
4545 usb_ugen_hdl_impl_t
*usb_ugen_hdl_impl
=
4546 (usb_ugen_hdl_impl_t
*)usb_ugen_hdl
;
4547 ugen_state_t
*ugenp
;
4550 if (usb_ugen_hdl
== NULL
) {
4552 return (USB_FAILURE
);
4555 ugenp
= usb_ugen_hdl_impl
->hdl_ugenp
;
4556 dip
= ugenp
->ug_dip
;
4558 if (ugenp
->ug_pm
== NULL
) {
4560 return (USB_SUCCESS
);
4563 USB_DPRINTF_L4(UGEN_PRINT_PM
, ugenp
->ug_log_hdl
,
4564 "usb_ugen_power: level=%d", level
);
4566 (void) usb_serialize_access(ugenp
->ug_ser_cookie
,
4569 * If we are disconnected/suspended, return success. Note that if we
4570 * return failure, bringing down the system will hang when
4571 * PM tries to power up all devices
4573 mutex_enter(&ugenp
->ug_mutex
);
4574 switch (ugenp
->ug_dev_state
) {
4575 case USB_DEV_ONLINE
:
4578 case USB_DEV_DISCONNECTED
:
4579 case USB_DEV_SUSPENDED
:
4580 case USB_UGEN_DEV_UNAVAILABLE_RESUME
:
4581 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT
:
4583 USB_DPRINTF_L2(UGEN_PRINT_PM
, ugenp
->ug_log_hdl
,
4584 "ugen_power: disconnected/suspended "
4585 "dev_state=%d", ugenp
->ug_dev_state
);
4593 /* Check if we are transitioning to a legal power level */
4594 if (USB_DEV_PWRSTATE_OK(pm
->pwr_states
, level
)) {
4595 USB_DPRINTF_L2(UGEN_PRINT_PM
, ugenp
->ug_log_hdl
,
4596 "ugen_power: illegal power level=%d "
4597 "pwr_states: 0x%x", level
, pm
->pwr_states
);
4603 case USB_DEV_OS_PWR_OFF
:
4604 switch (ugenp
->ug_dev_state
) {
4605 case USB_DEV_ONLINE
:
4606 /* Deny the powerdown request if the device is busy */
4607 if (ugenp
->ug_pm
->pwr_busy
!= 0) {
4611 ASSERT(ugenp
->ug_open_count
== 0);
4612 ASSERT(ugenp
->ug_pending_cmds
== 0);
4613 ugenp
->ug_pm
->pwr_current
= USB_DEV_OS_PWR_OFF
;
4614 mutex_exit(&ugenp
->ug_mutex
);
4616 /* Issue USB D3 command to the device here */
4617 rval
= usb_set_device_pwrlvl3(dip
);
4618 mutex_enter(&ugenp
->ug_mutex
);
4627 case USB_DEV_OS_FULL_PWR
:
4629 * PM framework tries to put us in full power during system
4632 switch (ugenp
->ug_dev_state
) {
4633 case USB_UGEN_DEV_UNAVAILABLE_RESUME
:
4634 case USB_UGEN_DEV_UNAVAILABLE_RECONNECT
:
4638 ugenp
->ug_dev_state
= USB_DEV_ONLINE
;
4640 /* wakeup devstat reads and polls */
4641 ugen_ds_change(ugenp
);
4642 ugen_ds_poll_wakeup(ugenp
);
4646 ugenp
->ug_pm
->pwr_current
= USB_DEV_OS_FULL_PWR
;
4647 mutex_exit(&ugenp
->ug_mutex
);
4648 rval
= usb_set_device_pwrlvl0(dip
);
4649 mutex_enter(&ugenp
->ug_mutex
);
4653 /* Levels 1 and 2 are not supported to keep it simple. */
4654 USB_DPRINTF_L2(UGEN_PRINT_PM
, ugenp
->ug_log_hdl
,
4655 "ugen_power: power level %d not supported", level
);
4660 mutex_exit(&ugenp
->ug_mutex
);
4661 usb_release_access(ugenp
->ug_ser_cookie
);
4668 ugen_pm_busy_component(ugen_state_t
*ugen_statep
)
4670 ASSERT(!mutex_owned(&ugen_statep
->ug_mutex
));
4672 if (ugen_statep
->ug_pm
!= NULL
) {
4673 mutex_enter(&ugen_statep
->ug_mutex
);
4674 ugen_statep
->ug_pm
->pwr_busy
++;
4676 USB_DPRINTF_L4(UGEN_PRINT_PM
, ugen_statep
->ug_log_hdl
,
4677 "ugen_pm_busy_component: %d", ugen_statep
->ug_pm
->pwr_busy
);
4679 mutex_exit(&ugen_statep
->ug_mutex
);
4680 if (pm_busy_component(ugen_statep
->ug_dip
, 0) != DDI_SUCCESS
) {
4681 mutex_enter(&ugen_statep
->ug_mutex
);
4682 ugen_statep
->ug_pm
->pwr_busy
--;
4684 USB_DPRINTF_L2(UGEN_PRINT_PM
, ugen_statep
->ug_log_hdl
,
4685 "ugen_pm_busy_component failed: %d",
4686 ugen_statep
->ug_pm
->pwr_busy
);
4688 mutex_exit(&ugen_statep
->ug_mutex
);
4695 ugen_pm_idle_component(ugen_state_t
*ugen_statep
)
4697 ASSERT(!mutex_owned(&ugen_statep
->ug_mutex
));
4699 if (ugen_statep
->ug_pm
!= NULL
) {
4700 if (pm_idle_component(ugen_statep
->ug_dip
, 0) == DDI_SUCCESS
) {
4701 mutex_enter(&ugen_statep
->ug_mutex
);
4702 ASSERT(ugen_statep
->ug_pm
->pwr_busy
> 0);
4703 ugen_statep
->ug_pm
->pwr_busy
--;
4705 USB_DPRINTF_L4(UGEN_PRINT_PM
, ugen_statep
->ug_log_hdl
,
4706 "ugen_pm_idle_component: %d",
4707 ugen_statep
->ug_pm
->pwr_busy
);
4709 mutex_exit(&ugen_statep
->ug_mutex
);
4716 * devt lookup support
4717 * In ugen_strategy and ugen_minphys, we only have the devt and need
4718 * the ugen_state pointer. Since we don't know instance mask, we can't
4719 * easily derive a softstate pointer. Therefore, we use a list
4722 ugen_store_devt(ugen_state_t
*ugenp
, minor_t minor
)
4724 ugen_devt_list_entry_t
*e
= kmem_zalloc(
4725 sizeof (ugen_devt_list_entry_t
), KM_SLEEP
);
4726 ugen_devt_list_entry_t
*t
;
4728 mutex_enter(&ugen_devt_list_mutex
);
4729 e
->list_dev
= makedevice(ddi_driver_major(ugenp
->ug_dip
), minor
);
4730 e
->list_state
= ugenp
;
4732 t
= ugen_devt_list
.list_next
;
4734 /* check if the entry is already in the list */
4736 ASSERT(t
->list_dev
!= e
->list_dev
);
4740 /* add to the head of the list */
4741 e
->list_next
= ugen_devt_list
.list_next
;
4742 if (ugen_devt_list
.list_next
) {
4743 ugen_devt_list
.list_next
->list_prev
= e
;
4745 ugen_devt_list
.list_next
= e
;
4746 mutex_exit(&ugen_devt_list_mutex
);
4750 static ugen_state_t
*
4751 ugen_devt2state(dev_t dev
)
4753 ugen_devt_list_entry_t
*t
;
4754 ugen_state_t
*ugenp
= NULL
;
4757 mutex_enter(&ugen_devt_list_mutex
);
4759 for (index
= ugen_devt_cache_index
, count
= 0;
4760 count
< UGEN_DEVT_CACHE_SIZE
; count
++) {
4761 if (ugen_devt_cache
[index
].cache_dev
== dev
) {
4762 ugen_devt_cache
[index
].cache_hit
++;
4763 ugenp
= ugen_devt_cache
[index
].cache_state
;
4765 mutex_exit(&ugen_devt_list_mutex
);
4770 index
%= UGEN_DEVT_CACHE_SIZE
;
4773 t
= ugen_devt_list
.list_next
;
4776 if (t
->list_dev
== dev
) {
4777 ugenp
= t
->list_state
;
4778 ugen_devt_cache_index
++;
4779 ugen_devt_cache_index
%= UGEN_DEVT_CACHE_SIZE
;
4780 ugen_devt_cache
[ugen_devt_cache_index
].cache_dev
= dev
;
4781 ugen_devt_cache
[ugen_devt_cache_index
].cache_state
=
4783 mutex_exit(&ugen_devt_list_mutex
);
4789 mutex_exit(&ugen_devt_list_mutex
);
4796 ugen_free_devt(ugen_state_t
*ugenp
)
4798 ugen_devt_list_entry_t
*e
, *next
, *prev
;
4799 major_t major
= ddi_driver_major(ugenp
->ug_dip
);
4800 int instance
= ddi_get_instance(ugenp
->ug_dip
);
4802 mutex_enter(&ugen_devt_list_mutex
);
4803 prev
= &ugen_devt_list
;
4804 for (e
= prev
->list_next
; e
!= 0; e
= next
) {
4805 int i
= (getminor(e
->list_dev
) &
4806 ugenp
->ug_hdl
->hdl_minor_node_instance_mask
) >>
4807 ugenp
->ug_hdl
->hdl_minor_node_instance_shift
;
4808 int m
= getmajor(e
->list_dev
);
4810 next
= e
->list_next
;
4812 if ((i
== instance
) && (m
== major
)) {
4813 prev
->list_next
= e
->list_next
;
4815 e
->list_next
->list_prev
= prev
;
4817 kmem_free(e
, sizeof (ugen_devt_list_entry_t
));
4823 bzero(ugen_devt_cache
, sizeof (ugen_devt_cache
));
4824 ugen_devt_cache_index
= 0;
4825 mutex_exit(&ugen_devt_list_mutex
);