17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5112116d8Sfb * Common Development and Distribution License (the "License").
6112116d8Sfb * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22ff0e937bSRaymond Chen * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
24e2c88f0cSGarrett D'Amore *
25e2c88f0cSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org>
26*0d2006e4SRobert Mustacchi * Copyright 2019 Joyent, Inc.
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support
327c478bd9Sstevel@tonic-gate *
337c478bd9Sstevel@tonic-gate * all functions exposed to client drivers have prefix usb_ while all USBA
347c478bd9Sstevel@tonic-gate * internal functions or functions exposed to HCD or hubd only have prefix
357c478bd9Sstevel@tonic-gate * usba_
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * this file contains all USBAI pipe management
387c478bd9Sstevel@tonic-gate * usb_pipe_open()
397c478bd9Sstevel@tonic-gate * usb_pipe_close()
407c478bd9Sstevel@tonic-gate * usb_pipe_set_private()
417c478bd9Sstevel@tonic-gate * usb_pipe_get_private()
427c478bd9Sstevel@tonic-gate * usb_pipe_abort()
437c478bd9Sstevel@tonic-gate * usb_pipe_reset()
447c478bd9Sstevel@tonic-gate * usb_pipe_drain_reqs()
457c478bd9Sstevel@tonic-gate */
467c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK
477c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
487c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
497c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate extern pri_t maxclsyspri;
527c478bd9Sstevel@tonic-gate extern pri_t minclsyspri;
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate /* function prototypes */
557c478bd9Sstevel@tonic-gate static void usba_pipe_do_async_func_thread(void *arg);
567c478bd9Sstevel@tonic-gate static int usba_pipe_sync_close(dev_info_t *, usba_ph_impl_t *,
577c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t);
587c478bd9Sstevel@tonic-gate static int usba_pipe_sync_reset(dev_info_t *, usba_ph_impl_t *,
597c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t);
607c478bd9Sstevel@tonic-gate static int usba_pipe_sync_drain_reqs(dev_info_t *, usba_ph_impl_t *,
617c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t);
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate /* local tunables */
644610e4a0Sfrits int usba_drain_timeout = 1000; /* in ms */
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate /* return the default pipe for this device */
677c478bd9Sstevel@tonic-gate usb_pipe_handle_t
usba_get_dflt_pipe_handle(dev_info_t * dip)687c478bd9Sstevel@tonic-gate usba_get_dflt_pipe_handle(dev_info_t *dip)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
717c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = NULL;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate if (dip) {
747c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
757c478bd9Sstevel@tonic-gate if (usba_device) {
767c478bd9Sstevel@tonic-gate pipe_handle =
777c478bd9Sstevel@tonic-gate (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate return (pipe_handle);
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate /* return dip owner of pipe_handle */
867c478bd9Sstevel@tonic-gate dev_info_t *
usba_get_dip(usb_pipe_handle_t pipe_handle)877c478bd9Sstevel@tonic-gate usba_get_dip(usb_pipe_handle_t pipe_handle)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
907c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL;
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate if (ph_impl) {
937c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
947c478bd9Sstevel@tonic-gate dip = ph_impl->usba_ph_dip;
957c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate return (dip);
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate usb_pipe_handle_t
usba_usbdev_to_dflt_pipe_handle(usba_device_t * usba_device)1037c478bd9Sstevel@tonic-gate usba_usbdev_to_dflt_pipe_handle(usba_device_t *usba_device)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = NULL;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate if ((usba_device) &&
1087c478bd9Sstevel@tonic-gate (usba_device->usb_ph_list[0].usba_ph_data != NULL)) {
1097c478bd9Sstevel@tonic-gate pipe_handle = (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate return (pipe_handle);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *
usba_get_ph_data(usb_pipe_handle_t pipe_handle)1177c478bd9Sstevel@tonic-gate usba_get_ph_data(usb_pipe_handle_t pipe_handle)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1207c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = NULL;
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate if (ph_impl) {
1237c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
1247c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_ref_count >= 0);
1257c478bd9Sstevel@tonic-gate ph_data = ph_impl->usba_ph_data;
1267c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate return (ph_data);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate usb_pipe_handle_t
usba_get_pipe_handle(usba_pipe_handle_data_t * ph_data)1347c478bd9Sstevel@tonic-gate usba_get_pipe_handle(usba_pipe_handle_data_t *ph_data)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph = NULL;
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate if (ph_data) {
1397c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
1407c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
1417c478bd9Sstevel@tonic-gate ph = (usb_pipe_handle_t)ph_data->p_ph_impl;
1427c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate return (ph);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate * opaque to pipe handle impl translation with incr of ref count. The caller
1517c478bd9Sstevel@tonic-gate * must release ph_data when done. Increment the ref count ensures that
1527c478bd9Sstevel@tonic-gate * the ph_data will not be freed underneath us.
1537c478bd9Sstevel@tonic-gate */
1547c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *
usba_hold_ph_data(usb_pipe_handle_t pipe_handle)1557c478bd9Sstevel@tonic-gate usba_hold_ph_data(usb_pipe_handle_t pipe_handle)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1587c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = NULL;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate if (ph_impl) {
1617c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate switch (ph_impl->usba_ph_state) {
1647c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_IDLE:
1657c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE:
1667c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ERROR:
1677c478bd9Sstevel@tonic-gate ph_data = ph_impl->usba_ph_data;
1687c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count++;
1697c478bd9Sstevel@tonic-gate break;
1707c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSED:
1717c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSING:
1727c478bd9Sstevel@tonic-gate default:
1737c478bd9Sstevel@tonic-gate break;
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1777c478bd9Sstevel@tonic-gate "usba_hold_ph_data: ph_impl=0x%p state=%d ref=%d",
178112116d8Sfb (void *)ph_impl, ph_impl->usba_ph_state,
1797c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count);
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate return (ph_data);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate void
usba_release_ph_data(usba_ph_impl_t * ph_impl)1897c478bd9Sstevel@tonic-gate usba_release_ph_data(usba_ph_impl_t *ph_impl)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate if (ph_impl) {
1927c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1957c478bd9Sstevel@tonic-gate "usba_release_ph_data: "
1967c478bd9Sstevel@tonic-gate "ph_impl=0x%p state=%d ref=%d",
197112116d8Sfb (void *)ph_impl, ph_impl->usba_ph_state,
1987c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count);
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate #ifndef __lock_lint
2017c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_data) {
2027c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2037c478bd9Sstevel@tonic-gate "usba_release_ph_data: req_count=%d",
2047c478bd9Sstevel@tonic-gate ph_impl->usba_ph_data->p_req_count);
2057c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_data->p_req_count >= 0);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate #endif
2087c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count--;
2097c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_ref_count >= 0);
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate * get pipe state from ph_data
2187c478bd9Sstevel@tonic-gate */
2197c478bd9Sstevel@tonic-gate usb_pipe_state_t
usba_get_ph_state(usba_pipe_handle_data_t * ph_data)2207c478bd9Sstevel@tonic-gate usba_get_ph_state(usba_pipe_handle_data_t *ph_data)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
2237c478bd9Sstevel@tonic-gate usb_pipe_state_t pipe_state;
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ph_data->p_mutex));
2267c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
2277c478bd9Sstevel@tonic-gate pipe_state = ph_impl->usba_ph_state;
2287c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate return (pipe_state);
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate * get ref_count from ph_data
2367c478bd9Sstevel@tonic-gate */
2377c478bd9Sstevel@tonic-gate int
usba_get_ph_ref_count(usba_pipe_handle_data_t * ph_data)2387c478bd9Sstevel@tonic-gate usba_get_ph_ref_count(usba_pipe_handle_data_t *ph_data)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
2417c478bd9Sstevel@tonic-gate int ref_count;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
2447c478bd9Sstevel@tonic-gate ref_count = ph_impl->usba_ph_ref_count;
2457c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate return (ref_count);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate * new pipe state
2537c478bd9Sstevel@tonic-gate * We need to hold both pipe mutex and ph_impl mutex
2547c478bd9Sstevel@tonic-gate */
2557c478bd9Sstevel@tonic-gate void
usba_pipe_new_state(usba_pipe_handle_data_t * ph_data,usb_pipe_state_t state)2567c478bd9Sstevel@tonic-gate usba_pipe_new_state(usba_pipe_handle_data_t *ph_data, usb_pipe_state_t state)
2577c478bd9Sstevel@tonic-gate {
2587c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ph_data->p_mutex));
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
2637c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
2647c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_ref_count >= 0);
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2677c478bd9Sstevel@tonic-gate "usba_pipe_new_state: "
2687c478bd9Sstevel@tonic-gate "ph_data=0x%p old=%s new=%s ref=%d req=%d",
269112116d8Sfb (void *)ph_data, usb_str_pipe_state(ph_impl->usba_ph_state),
2707c478bd9Sstevel@tonic-gate usb_str_pipe_state(state),
2717c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count, ph_data->p_req_count);
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate switch (ph_impl->usba_ph_state) {
2747c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_IDLE:
2757c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE:
2767c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ERROR:
2777c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSED:
2787c478bd9Sstevel@tonic-gate ph_impl->usba_ph_state = state;
2797c478bd9Sstevel@tonic-gate break;
2807c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSING:
2817c478bd9Sstevel@tonic-gate default:
2827c478bd9Sstevel@tonic-gate break;
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate * async function execution support
2907c478bd9Sstevel@tonic-gate * Arguments:
2917c478bd9Sstevel@tonic-gate * dip - devinfo pointer
2927c478bd9Sstevel@tonic-gate * sync_func - function to be executed
2937c478bd9Sstevel@tonic-gate * ph_impl - impl pipehandle
2947c478bd9Sstevel@tonic-gate * arg - opaque arg
2957c478bd9Sstevel@tonic-gate * usb_flags - none
2967c478bd9Sstevel@tonic-gate * callback - function to be called on completion, may be NULL
2977c478bd9Sstevel@tonic-gate * callback_arg - argument for callback function
2987c478bd9Sstevel@tonic-gate *
2997c478bd9Sstevel@tonic-gate * Note: The caller must do a hold on ph_data
3007c478bd9Sstevel@tonic-gate * We sleep for memory resources and taskq_dispatch which will ensure
3017c478bd9Sstevel@tonic-gate * that this function succeeds
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate int
usba_pipe_setup_func_call(dev_info_t * dip,int (* sync_func)(dev_info_t *,usba_ph_impl_t *,usba_pipe_async_req_t *,usb_flags_t),usba_ph_impl_t * ph_impl,usb_opaque_t arg,usb_flags_t usb_flags,void (* callback)(usb_pipe_handle_t,usb_opaque_t,int,usb_cb_flags_t),usb_opaque_t callback_arg)3047c478bd9Sstevel@tonic-gate usba_pipe_setup_func_call(
3057c478bd9Sstevel@tonic-gate dev_info_t *dip,
3067c478bd9Sstevel@tonic-gate int (*sync_func)(dev_info_t *,
3077c478bd9Sstevel@tonic-gate usba_ph_impl_t *, usba_pipe_async_req_t *,
3087c478bd9Sstevel@tonic-gate usb_flags_t),
3097c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
3107c478bd9Sstevel@tonic-gate usb_opaque_t arg,
3117c478bd9Sstevel@tonic-gate usb_flags_t usb_flags,
3127c478bd9Sstevel@tonic-gate void (*callback)(usb_pipe_handle_t,
3137c478bd9Sstevel@tonic-gate usb_opaque_t, int, usb_cb_flags_t),
3147c478bd9Sstevel@tonic-gate usb_opaque_t callback_arg)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request;
3177c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl;
3187c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
3197c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS;
3207c478bd9Sstevel@tonic-gate usb_cb_flags_t callback_flags;
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
3237c478bd9Sstevel@tonic-gate "usba_pipe_setup_func_call: ph_impl=0x%p, func=0x%p",
324112116d8Sfb (void *)ph_impl, (void *)sync_func);
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate if (((usb_flags & USB_FLAGS_SLEEP) == 0) && (callback == NULL)) {
3277c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
328d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3297c478bd9Sstevel@tonic-gate "usba_pipe_setup_func_call: async request with "
3307c478bd9Sstevel@tonic-gate "no callback");
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate request = kmem_zalloc(sizeof (usba_pipe_async_req_t), KM_SLEEP);
3367c478bd9Sstevel@tonic-gate request->dip = dip;
3377c478bd9Sstevel@tonic-gate request->ph_impl = ph_impl;
3387c478bd9Sstevel@tonic-gate request->arg = arg;
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate /*
3417c478bd9Sstevel@tonic-gate * OR in sleep flag. regardless of calling sync_func directly
3427c478bd9Sstevel@tonic-gate * or in a new thread, we will always wait for completion
3437c478bd9Sstevel@tonic-gate */
3447c478bd9Sstevel@tonic-gate request->usb_flags = usb_flags | USB_FLAGS_SLEEP;
3457c478bd9Sstevel@tonic-gate request->sync_func = sync_func;
3467c478bd9Sstevel@tonic-gate request->callback = callback;
3477c478bd9Sstevel@tonic-gate request->callback_arg = callback_arg;
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate if (usb_flags & USB_FLAGS_SLEEP) {
3507c478bd9Sstevel@tonic-gate rval = sync_func(dip, ph_impl, request, usb_flags);
3517c478bd9Sstevel@tonic-gate kmem_free(request, sizeof (usba_pipe_async_req_t));
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate } else if (usba_async_ph_req(ph_data,
3547c478bd9Sstevel@tonic-gate usba_pipe_do_async_func_thread,
3557c478bd9Sstevel@tonic-gate (void *)request, USB_FLAGS_SLEEP) != USB_SUCCESS) {
3567c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3577c478bd9Sstevel@tonic-gate "usb_async_req failed: ph_impl=0x%p, func=0x%p",
358112116d8Sfb (void *)ph_impl, (void *)sync_func);
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate if (callback) {
3617c478bd9Sstevel@tonic-gate callback_flags =
3627c478bd9Sstevel@tonic-gate usba_check_intr_context(USB_CB_ASYNC_REQ_FAILED);
3637c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, USB_FAILURE,
3647c478bd9Sstevel@tonic-gate callback_flags);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate kmem_free(request, sizeof (usba_pipe_async_req_t));
3687c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate return (rval);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate * taskq thread function to execute function synchronously
3777c478bd9Sstevel@tonic-gate * Note: caller must have done a hold on ph_data
3787c478bd9Sstevel@tonic-gate */
3797c478bd9Sstevel@tonic-gate static void
usba_pipe_do_async_func_thread(void * arg)3807c478bd9Sstevel@tonic-gate usba_pipe_do_async_func_thread(void *arg)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request = (usba_pipe_async_req_t *)arg;
3837c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = request->ph_impl;
3847c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl;
3857c478bd9Sstevel@tonic-gate int rval;
3867c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags = USB_CB_NO_INFO;
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate if ((rval = request->sync_func(request->dip, ph_impl,
3897c478bd9Sstevel@tonic-gate request, request->usb_flags | USB_FLAGS_SLEEP)) !=
3907c478bd9Sstevel@tonic-gate USB_SUCCESS) {
3917c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
3927c478bd9Sstevel@tonic-gate "sync func failed (%d)", rval);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate if (request->callback) {
3967c478bd9Sstevel@tonic-gate request->callback(pipe_handle, request->callback_arg, rval,
3977c478bd9Sstevel@tonic-gate cb_flags);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate kmem_free(request, sizeof (usba_pipe_async_req_t));
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate /*
4057c478bd9Sstevel@tonic-gate * default endpoint descriptor and pipe policy
4067c478bd9Sstevel@tonic-gate */
4077c478bd9Sstevel@tonic-gate usb_ep_descr_t usba_default_ep_descr =
4087c478bd9Sstevel@tonic-gate {7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0};
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate /* set some meaningful defaults */
4117c478bd9Sstevel@tonic-gate static usb_pipe_policy_t usba_default_ep_pipe_policy = {3};
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate * usb_get_ep_index: create an index from endpoint address that can
4167c478bd9Sstevel@tonic-gate * be used to index into endpoint pipe lists
4177c478bd9Sstevel@tonic-gate */
4187c478bd9Sstevel@tonic-gate uchar_t
usb_get_ep_index(uint8_t ep_addr)4197c478bd9Sstevel@tonic-gate usb_get_ep_index(uint8_t ep_addr)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate return ((ep_addr & USB_EP_NUM_MASK) +
4227c478bd9Sstevel@tonic-gate ((ep_addr & USB_EP_DIR_MASK) ? 16 : 0));
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate * pipe management
4287c478bd9Sstevel@tonic-gate * utility functions to init and destroy a pipehandle
4297c478bd9Sstevel@tonic-gate */
4307c478bd9Sstevel@tonic-gate static int
usba_init_pipe_handle(dev_info_t * dip,usba_device_t * usba_device,usb_ep_descr_t * ep,usb_ep_xdescr_t * ep_xdescr,usb_pipe_policy_t * pipe_policy,usba_ph_impl_t * ph_impl)4317c478bd9Sstevel@tonic-gate usba_init_pipe_handle(dev_info_t *dip,
4327c478bd9Sstevel@tonic-gate usba_device_t *usba_device,
4337c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep,
434993e3fafSRobert Mustacchi usb_ep_xdescr_t *ep_xdescr,
4357c478bd9Sstevel@tonic-gate usb_pipe_policy_t *pipe_policy,
4367c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl)
4377c478bd9Sstevel@tonic-gate {
438993e3fafSRobert Mustacchi usb_ep_xdescr_t xep;
4397c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip);
4407c478bd9Sstevel@tonic-gate unsigned int def_instance = instance;
4417c478bd9Sstevel@tonic-gate static unsigned int anon_instance = 0;
4427c478bd9Sstevel@tonic-gate char tq_name[TASKQ_NAMELEN];
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
4457c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie =
4467c478bd9Sstevel@tonic-gate usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
4477c478bd9Sstevel@tonic-gate hcdi_iblock_cookie;
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
4507c478bd9Sstevel@tonic-gate "usba_init_pipe_handle: "
451112116d8Sfb "usba_device=0x%p ep=0x%x", (void *)usba_device,
452112116d8Sfb ep->bEndpointAddress);
4537c478bd9Sstevel@tonic-gate mutex_init(&ph_data->p_mutex, NULL, MUTEX_DRIVER, iblock_cookie);
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate /* just to keep warlock happy, there is no contention yet */
4567c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
4577c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate ASSERT(pipe_policy->pp_max_async_reqs);
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate if (instance != -1) {
4627c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name),
4637c478bd9Sstevel@tonic-gate "USB_%s_%x_pipehndl_tq_%d",
4647c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress, instance);
4657c478bd9Sstevel@tonic-gate } else {
4661a5e258fSJosef 'Jeff' Sipek def_instance = atomic_inc_32_nv(&anon_instance);
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name),
4697c478bd9Sstevel@tonic-gate "USB_%s_%x_pipehndl_tq_%d_",
4707c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress, def_instance);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate ph_data->p_taskq = taskq_create(tq_name,
474112116d8Sfb pipe_policy->pp_max_async_reqs + 1,
475112116d8Sfb ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
476112116d8Sfb USB_EP_ATTR_ISOCH) ?
477112116d8Sfb (maxclsyspri - 5) : minclsyspri,
478112116d8Sfb 2 * (pipe_policy->pp_max_async_reqs + 1),
479112116d8Sfb 8 * (pipe_policy->pp_max_async_reqs + 1),
480112116d8Sfb TASKQ_PREPOPULATE);
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate * Create a shared taskq.
4847c478bd9Sstevel@tonic-gate */
4857c478bd9Sstevel@tonic-gate if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
4867c478bd9Sstevel@tonic-gate int iface = usb_get_if_number(dip);
4877c478bd9Sstevel@tonic-gate if (iface < 0) {
4887c478bd9Sstevel@tonic-gate /* we own the device, use first entry */
4897c478bd9Sstevel@tonic-gate iface = 0;
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate if (instance != -1) {
4937c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name),
4947c478bd9Sstevel@tonic-gate "USB_%s_%x_shared_tq_%d",
4957c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress,
4967c478bd9Sstevel@tonic-gate instance);
4977c478bd9Sstevel@tonic-gate } else {
4987c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name),
4997c478bd9Sstevel@tonic-gate "USB_%s_%x_shared_tq_%d_",
5007c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress,
5017c478bd9Sstevel@tonic-gate def_instance);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate if (usba_device->usb_shared_taskq_ref_count[iface] == 0) {
5057c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq[iface] =
5067c478bd9Sstevel@tonic-gate taskq_create(tq_name,
5077c478bd9Sstevel@tonic-gate 1, /* Number threads. */
5087c478bd9Sstevel@tonic-gate maxclsyspri - 5, /* Priority */
5097c478bd9Sstevel@tonic-gate 1, /* minalloc */
5107c478bd9Sstevel@tonic-gate USBA_N_ENDPOINTS + 4, /* maxalloc */
5117c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE);
5127c478bd9Sstevel@tonic-gate ASSERT(usba_device->usb_shared_taskq[iface] != NULL);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq_ref_count[iface]++;
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate
517993e3fafSRobert Mustacchi /*
518993e3fafSRobert Mustacchi * In the future, when we may have different versions of the extended
519993e3fafSRobert Mustacchi * endpoint descriptor, they should be normalized to the current version
520993e3fafSRobert Mustacchi * here such that all of the HCI drivers have a consistent view of the
521993e3fafSRobert Mustacchi * world. The extended descriptor may be NULL if we are opening the
522993e3fafSRobert Mustacchi * default control endpoint; however, we create a uniform view for the
523993e3fafSRobert Mustacchi * HCI drivers.
524993e3fafSRobert Mustacchi */
525993e3fafSRobert Mustacchi if (ep_xdescr == NULL) {
526993e3fafSRobert Mustacchi bzero(&xep, sizeof (usb_ep_xdescr_t));
527993e3fafSRobert Mustacchi xep.uex_version = USB_EP_XDESCR_CURRENT_VERSION;
528993e3fafSRobert Mustacchi xep.uex_ep = *ep;
529993e3fafSRobert Mustacchi ep_xdescr = &xep;
530993e3fafSRobert Mustacchi }
531993e3fafSRobert Mustacchi
5327c478bd9Sstevel@tonic-gate ph_data->p_dip = dip;
5337c478bd9Sstevel@tonic-gate ph_data->p_usba_device = usba_device;
5347c478bd9Sstevel@tonic-gate ph_data->p_ep = *ep;
535993e3fafSRobert Mustacchi ph_data->p_xep = *ep_xdescr;
5367c478bd9Sstevel@tonic-gate ph_data->p_ph_impl = ph_impl;
5377c478bd9Sstevel@tonic-gate if ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
5387c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) {
5397c478bd9Sstevel@tonic-gate ph_data->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /* fix up the MaxPacketSize if it is the default endpoint descr */
543*0d2006e4SRobert Mustacchi if (ep == &usba_default_ep_descr) {
544ff0e937bSRaymond Chen uint16_t maxpktsize;
545ff0e937bSRaymond Chen
546ff0e937bSRaymond Chen maxpktsize = usba_device->usb_dev_descr->bMaxPacketSize0;
5477c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
5487c478bd9Sstevel@tonic-gate "adjusting max packet size from %d to %d",
549ff0e937bSRaymond Chen ph_data->p_ep.wMaxPacketSize, maxpktsize);
5507c478bd9Sstevel@tonic-gate
551ff0e937bSRaymond Chen ph_data->p_ep.wMaxPacketSize = maxpktsize;
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate /* now update usba_ph_impl structure */
5557c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
5567c478bd9Sstevel@tonic-gate ph_impl->usba_ph_dip = dip;
5577c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ep = ph_data->p_ep;
5587c478bd9Sstevel@tonic-gate ph_impl->usba_ph_policy = ph_data->p_policy = *pipe_policy;
5597c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate usba_init_list(&ph_data->p_queue, (usb_opaque_t)ph_data, iblock_cookie);
5627c478bd9Sstevel@tonic-gate usba_init_list(&ph_data->p_cb_queue, (usb_opaque_t)ph_data,
563112116d8Sfb iblock_cookie);
5647c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
5657c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate static void
usba_taskq_destroy(void * arg)5727c478bd9Sstevel@tonic-gate usba_taskq_destroy(void *arg)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate taskq_destroy((taskq_t *)arg);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate static void
usba_destroy_pipe_handle(usba_pipe_handle_data_t * ph_data)5797c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(usba_pipe_handle_data_t *ph_data)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
5827c478bd9Sstevel@tonic-gate int timeout;
5837c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
586112116d8Sfb "usba_destroy_pipe_handle: ph_data=0x%p", (void *)ph_data);
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
5897c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate /* check for all activity to drain */
5927c478bd9Sstevel@tonic-gate for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
5937c478bd9Sstevel@tonic-gate if ((ph_impl->usba_ph_ref_count <= 1) &&
5947c478bd9Sstevel@tonic-gate (ph_data->p_req_count == 0)) {
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate break;
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5997c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
6007c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000));
6017c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
6027c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate * set state to closed here so any other thread
6077c478bd9Sstevel@tonic-gate * that is waiting for the CLOSED state will
6087c478bd9Sstevel@tonic-gate * continue. Otherwise, taskq_destroy might deadlock
6097c478bd9Sstevel@tonic-gate */
6107c478bd9Sstevel@tonic-gate ph_impl->usba_ph_data = NULL;
6117c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count = 0;
6127c478bd9Sstevel@tonic-gate ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSED;
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate if (ph_data->p_taskq) {
6157c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
6167c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
6177c478bd9Sstevel@tonic-gate if (taskq_member(ph_data->p_taskq, curthread)) {
6187c478bd9Sstevel@tonic-gate /*
6197c478bd9Sstevel@tonic-gate * use system taskq to destroy ph's taskq to avoid
6207c478bd9Sstevel@tonic-gate * deadlock
6217c478bd9Sstevel@tonic-gate */
6227c478bd9Sstevel@tonic-gate (void) taskq_dispatch(system_taskq,
6237c478bd9Sstevel@tonic-gate usba_taskq_destroy, ph_data->p_taskq, TQ_SLEEP);
6247c478bd9Sstevel@tonic-gate } else {
6257c478bd9Sstevel@tonic-gate taskq_destroy(ph_data->p_taskq);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate } else {
6287c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
6297c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
6337c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
6347c478bd9Sstevel@tonic-gate if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
6357c478bd9Sstevel@tonic-gate int iface = usb_get_if_number(ph_data->p_dip);
6367c478bd9Sstevel@tonic-gate if (iface < 0) {
6377c478bd9Sstevel@tonic-gate /* we own the device, use the first entry */
6387c478bd9Sstevel@tonic-gate iface = 0;
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
6417c478bd9Sstevel@tonic-gate if (--usba_device->usb_shared_taskq_ref_count[iface] == 0) {
6427c478bd9Sstevel@tonic-gate ph_data->p_spec_flag &= ~USBA_PH_FLAG_TQ_SHARE;
6437c478bd9Sstevel@tonic-gate if (taskq_member(usba_device->usb_shared_taskq[iface],
6447c478bd9Sstevel@tonic-gate curthread)) {
6457c478bd9Sstevel@tonic-gate (void) taskq_dispatch(
6467c478bd9Sstevel@tonic-gate system_taskq,
6477c478bd9Sstevel@tonic-gate usba_taskq_destroy,
6487c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq[iface],
6497c478bd9Sstevel@tonic-gate TQ_SLEEP);
6507c478bd9Sstevel@tonic-gate } else {
6517c478bd9Sstevel@tonic-gate taskq_destroy(
6527c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq[iface]);
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
661112116d8Sfb "usba_destroy_pipe_handle: destroying ph_data=0x%p",
662112116d8Sfb (void *)ph_data);
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate usba_destroy_list(&ph_data->p_queue);
6657c478bd9Sstevel@tonic-gate usba_destroy_list(&ph_data->p_cb_queue);
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate /* destroy mutexes */
6687c478bd9Sstevel@tonic-gate mutex_destroy(&ph_data->p_mutex);
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate kmem_free(ph_data, sizeof (usba_pipe_handle_data_t));
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate * usba_drain_cbs:
6767c478bd9Sstevel@tonic-gate * Drain the request callbacks on the pipe handle
6777c478bd9Sstevel@tonic-gate */
6787c478bd9Sstevel@tonic-gate int
usba_drain_cbs(usba_pipe_handle_data_t * ph_data,usb_cb_flags_t cb_flags,usb_cr_t cr)6797c478bd9Sstevel@tonic-gate usba_drain_cbs(usba_pipe_handle_data_t *ph_data, usb_cb_flags_t cb_flags,
6807c478bd9Sstevel@tonic-gate usb_cr_t cr)
6817c478bd9Sstevel@tonic-gate {
6827c478bd9Sstevel@tonic-gate usba_req_wrapper_t *req_wrp;
6837c478bd9Sstevel@tonic-gate int flush_requests = 1;
6847c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
6857c478bd9Sstevel@tonic-gate int timeout;
6867c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS;
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ph_data->p_mutex));
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
6917c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6927c478bd9Sstevel@tonic-gate "usba_drain_cbs: ph_data=0x%p ref=%d req=%d cb=0x%x cr=%d",
693112116d8Sfb (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count,
6947c478bd9Sstevel@tonic-gate cb_flags, cr);
6957c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
6967c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate if (ph_data->p_dip) {
6997c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) {
7007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI,
7017c478bd9Sstevel@tonic-gate usbai_log_handle,
7027c478bd9Sstevel@tonic-gate "no flushing on default pipe!");
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate flush_requests = 0;
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate if (flush_requests) {
7097c478bd9Sstevel@tonic-gate /* flush all requests in the pipehandle queue */
7107c478bd9Sstevel@tonic-gate while ((req_wrp = (usba_req_wrapper_t *)
7117c478bd9Sstevel@tonic-gate usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
7127c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
7137c478bd9Sstevel@tonic-gate usba_do_req_exc_cb(req_wrp, cr, cb_flags);
7147c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate /*
7197c478bd9Sstevel@tonic-gate * wait for any callbacks in progress but don't wait for
7207c478bd9Sstevel@tonic-gate * for queued requests on the default pipe
7217c478bd9Sstevel@tonic-gate */
7227c478bd9Sstevel@tonic-gate for (timeout = 0; (timeout < usba_drain_timeout) &&
7237c478bd9Sstevel@tonic-gate (ph_data->p_req_count >
7247c478bd9Sstevel@tonic-gate usba_list_entry_count(&ph_data->p_queue));
7257c478bd9Sstevel@tonic-gate timeout++) {
7267c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
7277c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000));
7287c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
7327c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
7337c478bd9Sstevel@tonic-gate "usba_drain_cbs done: ph_data=0x%p ref=%d req=%d",
734112116d8Sfb (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count);
7357c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate if (timeout == usba_drain_timeout) {
7387c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
7397c478bd9Sstevel@tonic-gate "draining callbacks timed out!");
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate rval = USB_FAILURE;
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate return (rval);
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate
7487c478bd9Sstevel@tonic-gate /*
7497c478bd9Sstevel@tonic-gate * usb_pipe_open():
7507c478bd9Sstevel@tonic-gate *
7517c478bd9Sstevel@tonic-gate * Before using any pipe including the default pipe, it should be opened
7527c478bd9Sstevel@tonic-gate * using usb_pipe_open(). On a successful open, a pipe handle is returned
7537c478bd9Sstevel@tonic-gate * for use in other usb_pipe_*() functions
7547c478bd9Sstevel@tonic-gate *
7557c478bd9Sstevel@tonic-gate * The default pipe can only be opened by the hub driver
7567c478bd9Sstevel@tonic-gate *
7577c478bd9Sstevel@tonic-gate * The bandwidth has been allocated and guaranteed on successful
7587c478bd9Sstevel@tonic-gate * opening of an isoc/intr pipes.
7597c478bd9Sstevel@tonic-gate *
7607c478bd9Sstevel@tonic-gate * Only the default pipe can be shared. all other control pipes
7617c478bd9Sstevel@tonic-gate * are excusively opened by default.
7627c478bd9Sstevel@tonic-gate * A pipe policy and endpoint descriptor must always be provided
7637c478bd9Sstevel@tonic-gate * except for default pipe
7647c478bd9Sstevel@tonic-gate *
7657c478bd9Sstevel@tonic-gate * Arguments:
7667c478bd9Sstevel@tonic-gate * dip - devinfo ptr
7677c478bd9Sstevel@tonic-gate * ep - endpoint descriptor pointer
7687c478bd9Sstevel@tonic-gate * pipe_policy - pointer to pipe policy which provides hints on how
7697c478bd9Sstevel@tonic-gate * the pipe will be used.
7707c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP wait for resources
7717c478bd9Sstevel@tonic-gate * to become available
7727c478bd9Sstevel@tonic-gate * pipe_handle - a pipe handle pointer. On a successful open,
7737c478bd9Sstevel@tonic-gate * a pipe_handle is returned in this pointer.
7747c478bd9Sstevel@tonic-gate *
7757c478bd9Sstevel@tonic-gate * Return values:
7767c478bd9Sstevel@tonic-gate * USB_SUCCESS - open succeeded
7777c478bd9Sstevel@tonic-gate * USB_FAILURE - unspecified open failure or pipe is already open
7787c478bd9Sstevel@tonic-gate * USB_NO_RESOURCES - no resources were available to complete the open
7797c478bd9Sstevel@tonic-gate * USB_NO_BANDWIDTH - no bandwidth available (isoc/intr pipes)
7807c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h
7817c478bd9Sstevel@tonic-gate */
7827c478bd9Sstevel@tonic-gate int
usb_pipe_xopen(dev_info_t * dip,usb_ep_xdescr_t * ep_xdesc,usb_pipe_policy_t * pipe_policy,usb_flags_t usb_flags,usb_pipe_handle_t * pipe_handle)783993e3fafSRobert Mustacchi usb_pipe_xopen(
7847c478bd9Sstevel@tonic-gate dev_info_t *dip,
785993e3fafSRobert Mustacchi usb_ep_xdescr_t *ep_xdesc,
7867c478bd9Sstevel@tonic-gate usb_pipe_policy_t *pipe_policy,
7877c478bd9Sstevel@tonic-gate usb_flags_t usb_flags,
7887c478bd9Sstevel@tonic-gate usb_pipe_handle_t *pipe_handle)
7897c478bd9Sstevel@tonic-gate {
790993e3fafSRobert Mustacchi usb_ep_descr_t *ep;
7917c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
7927c478bd9Sstevel@tonic-gate int rval;
7937c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data;
7947c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl;
7957c478bd9Sstevel@tonic-gate uchar_t ep_index;
7967c478bd9Sstevel@tonic-gate int kmflag;
7977c478bd9Sstevel@tonic-gate size_t size;
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
8007c478bd9Sstevel@tonic-gate "usb_pipe_open:\n\t"
801993e3fafSRobert Mustacchi "dip=0x%p ep_xdesc=0x%p pp=0x%p uf=0x%x ph=0x%p",
802993e3fafSRobert Mustacchi (void *)dip, (void *)ep_xdesc, (void *)pipe_policy, usb_flags,
803112116d8Sfb (void *)pipe_handle);
8047c478bd9Sstevel@tonic-gate
8057c478bd9Sstevel@tonic-gate if ((dip == NULL) || (pipe_handle == NULL)) {
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate
810993e3fafSRobert Mustacchi if ((ep_xdesc != NULL) &&
811993e3fafSRobert Mustacchi ((ep_xdesc->uex_version != USB_EP_XDESCR_CURRENT_VERSION) ||
812993e3fafSRobert Mustacchi ((ep_xdesc->uex_flags & ~USB_EP_XFLAGS_SS_COMP) != 0))) {
813993e3fafSRobert Mustacchi
814993e3fafSRobert Mustacchi return (USB_INVALID_ARGS);
815993e3fafSRobert Mustacchi }
816993e3fafSRobert Mustacchi
8177c478bd9Sstevel@tonic-gate if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
8227c478bd9Sstevel@tonic-gate
823993e3fafSRobert Mustacchi /*
824993e3fafSRobert Mustacchi * Check the device's speed. If we're being asked to open anything other
825993e3fafSRobert Mustacchi * than the default endpoint and the device is superspeed or greater and
826993e3fafSRobert Mustacchi * we only have a usb_ep_descr_t and not the full endpoint data, then
827993e3fafSRobert Mustacchi * this was coming through usb_pipe_open() and we need to fail this
828993e3fafSRobert Mustacchi * call.
829993e3fafSRobert Mustacchi *
830993e3fafSRobert Mustacchi * Some drivers technically cheat and open the default control endpoint
831993e3fafSRobert Mustacchi * even though they're not supposed to. ugen appears to be the main
832993e3fafSRobert Mustacchi * offender. To deal with this, we check to see if the endpoint
833993e3fafSRobert Mustacchi * descriptor bcmps to our default and give them a break, since we don't
834993e3fafSRobert Mustacchi * need extended info for default control endpoints.
835993e3fafSRobert Mustacchi */
836993e3fafSRobert Mustacchi if (ep_xdesc != NULL && ep_xdesc->uex_flags == 0 &&
837993e3fafSRobert Mustacchi bcmp(&ep_xdesc->uex_ep, &usba_default_ep_descr,
838993e3fafSRobert Mustacchi sizeof (usb_ep_descr_t)) != 0 &&
839993e3fafSRobert Mustacchi usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) {
840993e3fafSRobert Mustacchi const char *dname = ddi_driver_name(dip);
841993e3fafSRobert Mustacchi const char *prod, *mfg;
842993e3fafSRobert Mustacchi
843993e3fafSRobert Mustacchi prod = usba_device->usb_product_str;
844993e3fafSRobert Mustacchi if (prod == NULL)
845993e3fafSRobert Mustacchi prod = "Unknown Device";
846993e3fafSRobert Mustacchi mfg = usba_device->usb_mfg_str;
847993e3fafSRobert Mustacchi if (mfg == NULL)
848993e3fafSRobert Mustacchi mfg = "Unknown Manufacturer";
849993e3fafSRobert Mustacchi cmn_err(CE_NOTE, "driver %s attempting to open non-default "
850993e3fafSRobert Mustacchi "of a USB 3.0 or newer device through usb_pipe_open(). "
851993e3fafSRobert Mustacchi "%s must be updated to use usb_pipe_xopen() to work with "
852993e3fafSRobert Mustacchi "USB device %s %s.", dname, dname, mfg, prod);
853993e3fafSRobert Mustacchi return (USB_FAILURE);
854993e3fafSRobert Mustacchi }
855993e3fafSRobert Mustacchi
856993e3fafSRobert Mustacchi if ((ep_xdesc != NULL) && (pipe_policy == NULL)) {
8577c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8587c478bd9Sstevel@tonic-gate "usb_pipe_open: null pipe policy");
8597c478bd9Sstevel@tonic-gate
8607c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate
8637c478bd9Sstevel@tonic-gate /* is the device still connected? */
864993e3fafSRobert Mustacchi if ((ep_xdesc != NULL) & DEVI_IS_DEVICE_REMOVED(dip)) {
8657c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8667c478bd9Sstevel@tonic-gate "usb_pipe_open: device has been removed");
8677c478bd9Sstevel@tonic-gate
8687c478bd9Sstevel@tonic-gate return (USB_FAILURE);
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate
8727c478bd9Sstevel@tonic-gate /*
8737c478bd9Sstevel@tonic-gate * if a null endpoint pointer was passed, use the default
8747c478bd9Sstevel@tonic-gate * endpoint descriptor
8757c478bd9Sstevel@tonic-gate */
876993e3fafSRobert Mustacchi if (ep_xdesc == NULL) {
8777c478bd9Sstevel@tonic-gate if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
8787c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8797c478bd9Sstevel@tonic-gate "usb_pipe_open: not allowed to open def pipe");
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate ep = &usba_default_ep_descr;
8857c478bd9Sstevel@tonic-gate pipe_policy = &usba_default_ep_pipe_policy;
886993e3fafSRobert Mustacchi } else {
887993e3fafSRobert Mustacchi ep = &ep_xdesc->uex_ep;
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
8917c478bd9Sstevel@tonic-gate if (((ep->bmAttributes & USB_EP_ATTR_MASK) ==
8927c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) ||
8937c478bd9Sstevel@tonic-gate ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
8947c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH)) {
8957c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8967c478bd9Sstevel@tonic-gate "usb_pipe_open: shared taskq not allowed with "
8977c478bd9Sstevel@tonic-gate "ctrl or isoch pipe");
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate kmflag = (usb_flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
9047c478bd9Sstevel@tonic-gate size = sizeof (usba_pipe_handle_data_t);
9057c478bd9Sstevel@tonic-gate
9067c478bd9Sstevel@tonic-gate if ((ph_data = kmem_zalloc(size, kmflag)) == NULL) {
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /* check if pipe is already open and if so fail */
9127c478bd9Sstevel@tonic-gate ep_index = usb_get_ep_index(ep->bEndpointAddress);
9137c478bd9Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[ep_index];
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
9167c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_data) {
9197c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
9207c478bd9Sstevel@tonic-gate "usb_pipe_open: pipe to ep %d already open", ep_index);
9217c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
9227c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
9237c478bd9Sstevel@tonic-gate kmem_free(ph_data, size);
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate return (USB_BUSY);
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate ph_impl->usba_ph_data = ph_data;
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
9317c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
9347c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
9357c478bd9Sstevel@tonic-gate ph_data->p_spec_flag |= USBA_PH_FLAG_TQ_SHARE;
9367c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate /*
9407c478bd9Sstevel@tonic-gate * allocate and initialize the pipe handle
9417c478bd9Sstevel@tonic-gate */
9427c478bd9Sstevel@tonic-gate if ((rval = usba_init_pipe_handle(dip, usba_device,
943993e3fafSRobert Mustacchi ep, ep_xdesc, pipe_policy, ph_impl)) != USB_SUCCESS) {
9447c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
9457c478bd9Sstevel@tonic-gate "usb_pipe_open: pipe init failed (%d)", rval);
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate return (rval);
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate ph_data = ph_impl->usba_ph_data;
9507c478bd9Sstevel@tonic-gate
9517c478bd9Sstevel@tonic-gate /*
9527c478bd9Sstevel@tonic-gate * ask the hcd to open the pipe
9537c478bd9Sstevel@tonic-gate */
9547c478bd9Sstevel@tonic-gate if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_open(ph_data,
9557c478bd9Sstevel@tonic-gate usb_flags)) != USB_SUCCESS) {
9567c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(ph_data);
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate *pipe_handle = NULL;
9597c478bd9Sstevel@tonic-gate } else {
9607c478bd9Sstevel@tonic-gate *pipe_handle = (usb_pipe_handle_t)ph_impl;
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate /* set the pipe state after a successful hcd open */
9637c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
9647c478bd9Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
9657c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
969112116d8Sfb "usb_pipe_open: ph_impl=0x%p (0x%p)",
970112116d8Sfb (void *)ph_impl, (void *)ph_data);
9717c478bd9Sstevel@tonic-gate
9727c478bd9Sstevel@tonic-gate return (rval);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate
975993e3fafSRobert Mustacchi int
usb_pipe_open(dev_info_t * dip,usb_ep_descr_t * ep,usb_pipe_policy_t * pipe_policy,usb_flags_t usb_flags,usb_pipe_handle_t * pipe_handle)976993e3fafSRobert Mustacchi usb_pipe_open(
977993e3fafSRobert Mustacchi dev_info_t *dip,
978993e3fafSRobert Mustacchi usb_ep_descr_t *ep,
979993e3fafSRobert Mustacchi usb_pipe_policy_t *pipe_policy,
980993e3fafSRobert Mustacchi usb_flags_t usb_flags,
981993e3fafSRobert Mustacchi usb_pipe_handle_t *pipe_handle)
982993e3fafSRobert Mustacchi {
983993e3fafSRobert Mustacchi usb_ep_xdescr_t xdesc, *xp = NULL;
984993e3fafSRobert Mustacchi
985993e3fafSRobert Mustacchi /*
986993e3fafSRobert Mustacchi * ep may be NULL if trying to open the default control endpoint.
987993e3fafSRobert Mustacchi */
988993e3fafSRobert Mustacchi if (ep != NULL) {
989993e3fafSRobert Mustacchi bzero(&xdesc, sizeof (usb_ep_xdescr_t));
990993e3fafSRobert Mustacchi xdesc.uex_version = USB_EP_XDESCR_CURRENT_VERSION;
991993e3fafSRobert Mustacchi xdesc.uex_ep = *ep;
992993e3fafSRobert Mustacchi xp = &xdesc;
993993e3fafSRobert Mustacchi }
994993e3fafSRobert Mustacchi
995993e3fafSRobert Mustacchi return (usb_pipe_xopen(dip, xp, pipe_policy, usb_flags,
996993e3fafSRobert Mustacchi pipe_handle));
997993e3fafSRobert Mustacchi }
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gate /*
10007c478bd9Sstevel@tonic-gate * usb_pipe_close/sync_close:
10017c478bd9Sstevel@tonic-gate *
10027c478bd9Sstevel@tonic-gate * Close a pipe and release all resources and free the pipe_handle.
10037c478bd9Sstevel@tonic-gate * Automatic polling, if active, will be terminated
10047c478bd9Sstevel@tonic-gate *
10057c478bd9Sstevel@tonic-gate * Arguments:
10067c478bd9Sstevel@tonic-gate * dip - devinfo ptr
10077c478bd9Sstevel@tonic-gate * pipehandle - pointer to pipehandle. The pipehandle will be
10087c478bd9Sstevel@tonic-gate * zeroed on successful completion
10097c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP:
10107c478bd9Sstevel@tonic-gate * wait for resources, pipe
10117c478bd9Sstevel@tonic-gate * to become free, all callbacks completed
10127c478bd9Sstevel@tonic-gate * callback - If USB_FLAGS_SLEEP has not been specified, a
10137c478bd9Sstevel@tonic-gate * callback will be performed.
10147c478bd9Sstevel@tonic-gate * callback_arg - the first argument of the callback. Note that
10157c478bd9Sstevel@tonic-gate * the pipehandle will be zeroed and not passed
10167c478bd9Sstevel@tonic-gate *
10177c478bd9Sstevel@tonic-gate * Notes:
10187c478bd9Sstevel@tonic-gate * Pipe close will always succeed regardless whether USB_FLAGS_SLEEP has been
10197c478bd9Sstevel@tonic-gate * specified or not.
10207c478bd9Sstevel@tonic-gate * An async close will always succeed if the hint in the pipe policy
10217c478bd9Sstevel@tonic-gate * has been correct about the max number of async taskq requests required.
10227c478bd9Sstevel@tonic-gate * If there are really no resources, the pipe handle will be linked into
10237c478bd9Sstevel@tonic-gate * a garbage pipe list and periodically checked by USBA until it can be
10247c478bd9Sstevel@tonic-gate * closed. This may cause a hang in the detach of the driver.
10257c478bd9Sstevel@tonic-gate * USBA will prevent the client from submitting more requests to a pipe
10267c478bd9Sstevel@tonic-gate * that is being closed
10277c478bd9Sstevel@tonic-gate * Subsequent usb_pipe_close() requests on the same pipe to USBA will
10287c478bd9Sstevel@tonic-gate * wait for the previous close(s) to finish.
10297c478bd9Sstevel@tonic-gate *
10307c478bd9Sstevel@tonic-gate * Note that once we start closing a pipe, we cannot go back anymore
10317c478bd9Sstevel@tonic-gate * to a normal pipe state
10327c478bd9Sstevel@tonic-gate */
10337c478bd9Sstevel@tonic-gate void
usb_pipe_close(dev_info_t * dip,usb_pipe_handle_t pipe_handle,usb_flags_t usb_flags,void (* callback)(usb_pipe_handle_t pipe_handle,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t callback_arg)10347c478bd9Sstevel@tonic-gate usb_pipe_close(dev_info_t *dip,
10357c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle,
10367c478bd9Sstevel@tonic-gate usb_flags_t usb_flags,
10377c478bd9Sstevel@tonic-gate void (*callback)(
10387c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle,
10397c478bd9Sstevel@tonic-gate usb_opaque_t arg,
10407c478bd9Sstevel@tonic-gate int rval,
10417c478bd9Sstevel@tonic-gate usb_cb_flags_t flags),
10427c478bd9Sstevel@tonic-gate usb_opaque_t callback_arg)
10437c478bd9Sstevel@tonic-gate {
10447c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data;
10457c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
10467c478bd9Sstevel@tonic-gate usb_cb_flags_t callback_flags;
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1049112116d8Sfb "usb_pipe_close: ph=0x%p", (void *)pipe_handle);
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
10527c478bd9Sstevel@tonic-gate if ((dip == NULL) || (pipe_handle == NULL)) {
10537c478bd9Sstevel@tonic-gate if (callback) {
10547c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg,
10557c478bd9Sstevel@tonic-gate USB_INVALID_ARGS, callback_flags);
10567c478bd9Sstevel@tonic-gate } else {
1057d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI,
10587c478bd9Sstevel@tonic-gate usbai_log_handle,
10597c478bd9Sstevel@tonic-gate "usb_pipe_close: invalid arguments");
10607c478bd9Sstevel@tonic-gate }
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate return;
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
10667c478bd9Sstevel@tonic-gate /*
10677c478bd9Sstevel@tonic-gate * It is the client driver doing the pipe close,
10687c478bd9Sstevel@tonic-gate * the pipe is no longer persistent then.
10697c478bd9Sstevel@tonic-gate */
10707c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
10717c478bd9Sstevel@tonic-gate ph_impl->usba_ph_flags &= ~USBA_PH_DATA_PERSISTENT;
10727c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate
10757c478bd9Sstevel@tonic-gate if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
10767c478bd9Sstevel@tonic-gate if (callback) {
10777c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg,
10787c478bd9Sstevel@tonic-gate USB_INVALID_CONTEXT, callback_flags);
10797c478bd9Sstevel@tonic-gate } else {
1080d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI,
10817c478bd9Sstevel@tonic-gate usbai_log_handle,
10827c478bd9Sstevel@tonic-gate "usb_pipe_close: invalid context");
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate
10857c478bd9Sstevel@tonic-gate return;
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gate /* hold pipehandle anyways since we will decrement later */
10917c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
10927c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count++;
10937c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
10967c478bd9Sstevel@tonic-gate ph_impl, NULL, usb_flags, callback, callback_arg);
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate return;
10997c478bd9Sstevel@tonic-gate }
11007c478bd9Sstevel@tonic-gate
11017c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data) &&
11047c478bd9Sstevel@tonic-gate ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0)) {
1105d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11067c478bd9Sstevel@tonic-gate "usb_pipe_close: not allowed to close def pipe");
11077c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
11087c478bd9Sstevel@tonic-gate
11097c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate if (callback) {
11127c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg,
11137c478bd9Sstevel@tonic-gate USB_INVALID_PIPE, callback_flags);
11147c478bd9Sstevel@tonic-gate } else {
1115d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI,
11167c478bd9Sstevel@tonic-gate usbai_log_handle,
11177c478bd9Sstevel@tonic-gate "usb_pipe_close: invalid pipe");
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate return;
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate
11237c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
11267c478bd9Sstevel@tonic-gate ph_impl, NULL, usb_flags, callback, callback_arg);
11277c478bd9Sstevel@tonic-gate }
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11317c478bd9Sstevel@tonic-gate static int
usba_pipe_sync_close(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t usb_flags)11327c478bd9Sstevel@tonic-gate usba_pipe_sync_close(dev_info_t *dip, usba_ph_impl_t *ph_impl,
11337c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, usb_flags_t usb_flags)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
11367c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
1137112116d8Sfb (usb_pipe_handle_t)ph_impl);
11387c478bd9Sstevel@tonic-gate int attribute;
11397c478bd9Sstevel@tonic-gate uchar_t dir;
11407c478bd9Sstevel@tonic-gate int timeout;
11417c478bd9Sstevel@tonic-gate
11427c478bd9Sstevel@tonic-gate if (ph_impl == NULL) {
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate
11477c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
11487c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11497c478bd9Sstevel@tonic-gate "usba_pipe_sync_close: dip=0x%p ph_data=0x%p state=%d ref=%d",
1150112116d8Sfb (void *)dip, (void *)ph_data, ph_impl->usba_ph_state,
1151112116d8Sfb ph_impl->usba_ph_ref_count);
11527c478bd9Sstevel@tonic-gate
11537c478bd9Sstevel@tonic-gate /*
11547c478bd9Sstevel@tonic-gate * if another thread opens the pipe again, this loop could
11557c478bd9Sstevel@tonic-gate * be truly forever
11567c478bd9Sstevel@tonic-gate */
11577c478bd9Sstevel@tonic-gate if ((ph_data == NULL) ||
11587c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSING) ||
11597c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSED)) {
11607c478bd9Sstevel@tonic-gate /* wait forever till really closed */
11617c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
11627c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
11637c478bd9Sstevel@tonic-gate
11647c478bd9Sstevel@tonic-gate while (usba_get_ph_data((usb_pipe_handle_t)ph_impl)) {
11657c478bd9Sstevel@tonic-gate delay(1);
11667c478bd9Sstevel@tonic-gate }
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSING;
11717c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
11747c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
11757c478bd9Sstevel@tonic-gate
11767c478bd9Sstevel@tonic-gate attribute = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
11777c478bd9Sstevel@tonic-gate dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate /*
11827c478bd9Sstevel@tonic-gate * For control and bulk, we will drain till ref_count <= 1 and
11837c478bd9Sstevel@tonic-gate * req_count == 0 but for isoc and intr IN, we can only wait
11847c478bd9Sstevel@tonic-gate * till the ref_count === 1 as the req_count will never go to 0
11857c478bd9Sstevel@tonic-gate */
11867c478bd9Sstevel@tonic-gate for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
11877c478bd9Sstevel@tonic-gate switch (attribute) {
11887c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
11897c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK:
11907c478bd9Sstevel@tonic-gate if ((ph_data->p_req_count == 0) &&
11917c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_ref_count <= 1)) {
11927c478bd9Sstevel@tonic-gate goto done;
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate break;
11957c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
11967c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
11977c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) {
11987c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_ref_count <= 1) {
11997c478bd9Sstevel@tonic-gate goto done;
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate } else if ((ph_data->p_req_count == 0) &&
12027c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_ref_count <= 1)) {
12037c478bd9Sstevel@tonic-gate goto done;
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate break;
12067c478bd9Sstevel@tonic-gate }
12077c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
12087c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
12097c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000));
12107c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
12117c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate done:
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
12167c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate if (timeout >= usba_drain_timeout) {
12197c478bd9Sstevel@tonic-gate int draining_succeeded;
12207c478bd9Sstevel@tonic-gate
12217c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
12227c478bd9Sstevel@tonic-gate "timeout on draining requests, resetting pipe 0x%p",
1223112116d8Sfb (void *)ph_impl);
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
12267c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP);
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
12297c478bd9Sstevel@tonic-gate draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1230112116d8Sfb USB_CR_PIPE_RESET);
12317c478bd9Sstevel@tonic-gate /* this MUST have succeeded */
12327c478bd9Sstevel@tonic-gate ASSERT(draining_succeeded == USB_SUCCESS);
12337c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
12367c478bd9Sstevel@tonic-gate "draining requests done");
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate
12397c478bd9Sstevel@tonic-gate if (usba_device->usb_hcdi_ops->usba_hcdi_pipe_close(ph_data,
12407c478bd9Sstevel@tonic-gate usb_flags) != USB_SUCCESS) {
1241d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
12427c478bd9Sstevel@tonic-gate "usba_pipe_sync_close: hcd close failed");
12437c478bd9Sstevel@tonic-gate /* carry on regardless! */
12447c478bd9Sstevel@tonic-gate }
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(ph_data);
12477c478bd9Sstevel@tonic-gate
12487c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate
12527c478bd9Sstevel@tonic-gate /*
12537c478bd9Sstevel@tonic-gate * usb_pipe_set_private:
12547c478bd9Sstevel@tonic-gate * set private client date in the pipe handle
12557c478bd9Sstevel@tonic-gate */
12567c478bd9Sstevel@tonic-gate int
usb_pipe_set_private(usb_pipe_handle_t pipe_handle,usb_opaque_t data)12577c478bd9Sstevel@tonic-gate usb_pipe_set_private(usb_pipe_handle_t pipe_handle, usb_opaque_t data)
12587c478bd9Sstevel@tonic-gate {
12597c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12627c478bd9Sstevel@tonic-gate "usb_pipe_set_private: ");
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate if (ph_data == NULL) {
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE);
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) {
12697c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM);
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate
12747c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
12757c478bd9Sstevel@tonic-gate ph_data->p_client_private = data;
12767c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
12777c478bd9Sstevel@tonic-gate
12787c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate
12847c478bd9Sstevel@tonic-gate /*
12857c478bd9Sstevel@tonic-gate * usb_pipe_get_private:
12867c478bd9Sstevel@tonic-gate * get private client date from the pipe handle
12877c478bd9Sstevel@tonic-gate */
12887c478bd9Sstevel@tonic-gate usb_opaque_t
usb_pipe_get_private(usb_pipe_handle_t pipe_handle)12897c478bd9Sstevel@tonic-gate usb_pipe_get_private(usb_pipe_handle_t pipe_handle)
12907c478bd9Sstevel@tonic-gate {
12917c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
12927c478bd9Sstevel@tonic-gate usb_opaque_t data;
12937c478bd9Sstevel@tonic-gate
12947c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12957c478bd9Sstevel@tonic-gate "usb_pipe_get_private:");
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate if (ph_data == NULL) {
12987c478bd9Sstevel@tonic-gate
12997c478bd9Sstevel@tonic-gate return (NULL);
13007c478bd9Sstevel@tonic-gate }
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
13037c478bd9Sstevel@tonic-gate data = ph_data->p_client_private;
13047c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
13057c478bd9Sstevel@tonic-gate
13067c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
13077c478bd9Sstevel@tonic-gate
13087c478bd9Sstevel@tonic-gate return (data);
13097c478bd9Sstevel@tonic-gate }
13107c478bd9Sstevel@tonic-gate
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate /*
13137c478bd9Sstevel@tonic-gate * usb_pipe_reset
13147c478bd9Sstevel@tonic-gate * Arguments:
13157c478bd9Sstevel@tonic-gate * dip - devinfo pointer
13167c478bd9Sstevel@tonic-gate * pipe_handle - opaque pipe handle
13177c478bd9Sstevel@tonic-gate * Returns:
13187c478bd9Sstevel@tonic-gate * USB_SUCCESS - pipe successfully reset or request queued
13197c478bd9Sstevel@tonic-gate * USB_FAILURE - undetermined failure
13207c478bd9Sstevel@tonic-gate * USB_INVALID_PIPE - pipe is invalid or already closed
13217c478bd9Sstevel@tonic-gate */
13227c478bd9Sstevel@tonic-gate void
usb_pipe_reset(dev_info_t * dip,usb_pipe_handle_t pipe_handle,usb_flags_t usb_flags,void (* callback)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t callback_arg)13237c478bd9Sstevel@tonic-gate usb_pipe_reset(dev_info_t *dip,
13247c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle,
13257c478bd9Sstevel@tonic-gate usb_flags_t usb_flags,
13267c478bd9Sstevel@tonic-gate void (*callback)(
13277c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph,
13287c478bd9Sstevel@tonic-gate usb_opaque_t arg,
13297c478bd9Sstevel@tonic-gate int rval,
13307c478bd9Sstevel@tonic-gate usb_cb_flags_t flags),
13317c478bd9Sstevel@tonic-gate usb_opaque_t callback_arg)
13327c478bd9Sstevel@tonic-gate {
13337c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
13347c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
13357c478bd9Sstevel@tonic-gate usb_cb_flags_t callback_flags;
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13387c478bd9Sstevel@tonic-gate "usb_pipe_reset: dip=0x%p ph=0x%p uf=0x%x",
1339112116d8Sfb (void *)dip, (void *)pipe_handle, usb_flags);
13407c478bd9Sstevel@tonic-gate
13417c478bd9Sstevel@tonic-gate callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
13427c478bd9Sstevel@tonic-gate
13437c478bd9Sstevel@tonic-gate if ((dip == NULL) || (ph_data == NULL)) {
13447c478bd9Sstevel@tonic-gate if (callback) {
13457c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg,
13467c478bd9Sstevel@tonic-gate USB_INVALID_ARGS, callback_flags);
13477c478bd9Sstevel@tonic-gate } else {
1348d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI,
13497c478bd9Sstevel@tonic-gate usbai_log_handle,
13507c478bd9Sstevel@tonic-gate "usb_pipe_reset: invalid arguments");
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate return;
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
13587c478bd9Sstevel@tonic-gate if (callback) {
13597c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg,
13607c478bd9Sstevel@tonic-gate USB_INVALID_CONTEXT, callback_flags);
13617c478bd9Sstevel@tonic-gate } else {
1362d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI,
13637c478bd9Sstevel@tonic-gate usbai_log_handle,
13647c478bd9Sstevel@tonic-gate "usb_pipe_reset: invalid context");
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate
13677c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate return;
13707c478bd9Sstevel@tonic-gate }
13717c478bd9Sstevel@tonic-gate
13727c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate /* is this the default pipe? */
13757c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) {
13767c478bd9Sstevel@tonic-gate if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
1377d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
13787c478bd9Sstevel@tonic-gate "usb_pipe_reset: not allowed to reset def pipe");
13797c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
13807c478bd9Sstevel@tonic-gate
13817c478bd9Sstevel@tonic-gate if (callback) {
13827c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg,
13837c478bd9Sstevel@tonic-gate USB_INVALID_PIPE, callback_flags);
13847c478bd9Sstevel@tonic-gate } else {
1385d291d9f2Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI,
13867c478bd9Sstevel@tonic-gate usbai_log_handle,
13877c478bd9Sstevel@tonic-gate "usb_pipe_reset: invalid pipe");
13887c478bd9Sstevel@tonic-gate }
13897c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
13907c478bd9Sstevel@tonic-gate
13917c478bd9Sstevel@tonic-gate return;
13927c478bd9Sstevel@tonic-gate }
13937c478bd9Sstevel@tonic-gate }
13947c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip,
13977c478bd9Sstevel@tonic-gate usba_pipe_sync_reset, ph_impl, NULL, usb_flags, callback,
13987c478bd9Sstevel@tonic-gate callback_arg);
13997c478bd9Sstevel@tonic-gate }
14007c478bd9Sstevel@tonic-gate
14017c478bd9Sstevel@tonic-gate
14027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14037c478bd9Sstevel@tonic-gate int
usba_pipe_sync_reset(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t usb_flags)14047c478bd9Sstevel@tonic-gate usba_pipe_sync_reset(dev_info_t *dip,
14057c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
14067c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request,
14077c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
14087c478bd9Sstevel@tonic-gate {
14097c478bd9Sstevel@tonic-gate int rval, draining_succeeded;
14107c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1411112116d8Sfb ph_impl);
14127c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14157c478bd9Sstevel@tonic-gate "usba_pipe_sync_reset: dip=0x%p ph_data=0x%p uf=0x%x",
1416112116d8Sfb (void *)dip, (void *)ph_data, usb_flags);
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
14197c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
14207c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
14217c478bd9Sstevel@tonic-gate
14227c478bd9Sstevel@tonic-gate rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1423112116d8Sfb usb_flags);
14247c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate /*
14277c478bd9Sstevel@tonic-gate * The host controller has stopped polling of the endpoint.
14287c478bd9Sstevel@tonic-gate */
14297c478bd9Sstevel@tonic-gate draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1430112116d8Sfb USB_CR_PIPE_RESET);
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate /* this MUST have succeeded */
14337c478bd9Sstevel@tonic-gate ASSERT(draining_succeeded == USB_SUCCESS);
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
14367c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate /*
14397c478bd9Sstevel@tonic-gate * if there are requests still queued on the default pipe,
14407c478bd9Sstevel@tonic-gate * start them now
14417c478bd9Sstevel@tonic-gate */
14427c478bd9Sstevel@tonic-gate usba_start_next_req(ph_data);
14437c478bd9Sstevel@tonic-gate
14447c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate return (rval);
14477c478bd9Sstevel@tonic-gate }
14487c478bd9Sstevel@tonic-gate
14497c478bd9Sstevel@tonic-gate
14507c478bd9Sstevel@tonic-gate /*
14517c478bd9Sstevel@tonic-gate * usba_pipe_clear:
14527c478bd9Sstevel@tonic-gate * call hcd to clear pipe but don't wait for draining
14537c478bd9Sstevel@tonic-gate */
14547c478bd9Sstevel@tonic-gate void
usba_pipe_clear(usb_pipe_handle_t pipe_handle)14557c478bd9Sstevel@tonic-gate usba_pipe_clear(usb_pipe_handle_t pipe_handle)
14567c478bd9Sstevel@tonic-gate {
14577c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data(pipe_handle);
14587c478bd9Sstevel@tonic-gate usba_device_t *usba_device;
14597c478bd9Sstevel@tonic-gate usba_req_wrapper_t *req_wrp;
14607c478bd9Sstevel@tonic-gate int flush_requests = 1;
14617c478bd9Sstevel@tonic-gate
14627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1463112116d8Sfb "usba_pipe_clear: ph_data=0x%p", (void *)ph_data);
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate if (ph_data == NULL) {
14667c478bd9Sstevel@tonic-gate
14677c478bd9Sstevel@tonic-gate return;
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate
14707c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
14717c478bd9Sstevel@tonic-gate if (USBA_PIPE_CLOSING(usba_get_ph_state(ph_data))) {
14727c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate return;
14757c478bd9Sstevel@tonic-gate }
14767c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
14777c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
14787c478bd9Sstevel@tonic-gate
14797c478bd9Sstevel@tonic-gate (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1480112116d8Sfb USB_FLAGS_SLEEP);
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
14837c478bd9Sstevel@tonic-gate if (ph_data->p_dip) {
14847c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) {
14857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI,
14867c478bd9Sstevel@tonic-gate usbai_log_handle,
14877c478bd9Sstevel@tonic-gate "no flushing on default pipe!");
14887c478bd9Sstevel@tonic-gate
14897c478bd9Sstevel@tonic-gate flush_requests = 0;
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate if (flush_requests) {
14947c478bd9Sstevel@tonic-gate /* flush all requests in the pipehandle queue */
14957c478bd9Sstevel@tonic-gate while ((req_wrp = (usba_req_wrapper_t *)
14967c478bd9Sstevel@tonic-gate usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
14977c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
14987c478bd9Sstevel@tonic-gate usba_do_req_exc_cb(req_wrp, USB_CR_FLUSHED,
1499112116d8Sfb USB_CB_RESET_PIPE);
15007c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate }
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
15057c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate /*
15107c478bd9Sstevel@tonic-gate *
15117c478bd9Sstevel@tonic-gate * usb_pipe_drain_reqs
15127c478bd9Sstevel@tonic-gate * this function blocks until there are no more requests
15137c478bd9Sstevel@tonic-gate * owned by this dip on the pipe
15147c478bd9Sstevel@tonic-gate *
15157c478bd9Sstevel@tonic-gate * Arguments:
15167c478bd9Sstevel@tonic-gate * dip - devinfo pointer
15177c478bd9Sstevel@tonic-gate * pipe_handle - opaque pipe handle
15187c478bd9Sstevel@tonic-gate * timeout - timeout in seconds
15197c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP:
15207c478bd9Sstevel@tonic-gate * wait for completion.
15217c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified
15227c478bd9Sstevel@tonic-gate * this callback function will be called on
15237c478bd9Sstevel@tonic-gate * completion. This callback may be NULL
15247c478bd9Sstevel@tonic-gate * and no notification of completion will then
15257c478bd9Sstevel@tonic-gate * be provided.
15267c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function.
15277c478bd9Sstevel@tonic-gate *
15287c478bd9Sstevel@tonic-gate * callback and callback_arg should be NULL if USB_FLAGS_SLEEP has
15297c478bd9Sstevel@tonic-gate * been specified
15307c478bd9Sstevel@tonic-gate *
15317c478bd9Sstevel@tonic-gate * Returns:
15327c478bd9Sstevel@tonic-gate * USB_SUCCESS - pipe successfully reset or request queued
15337c478bd9Sstevel@tonic-gate * USB_FAILURE - timeout
15347c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h
15357c478bd9Sstevel@tonic-gate */
15367c478bd9Sstevel@tonic-gate int
usb_pipe_drain_reqs(dev_info_t * dip,usb_pipe_handle_t pipe_handle,uint_t time,usb_flags_t usb_flags,void (* cb)(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags),usb_opaque_t cb_arg)15377c478bd9Sstevel@tonic-gate usb_pipe_drain_reqs(dev_info_t *dip,
15387c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle,
15397c478bd9Sstevel@tonic-gate uint_t time,
15407c478bd9Sstevel@tonic-gate usb_flags_t usb_flags,
15417c478bd9Sstevel@tonic-gate void (*cb)(
15427c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph,
15437c478bd9Sstevel@tonic-gate usb_opaque_t arg, /* cb arg */
15447c478bd9Sstevel@tonic-gate int rval,
15457c478bd9Sstevel@tonic-gate usb_cb_flags_t flags),
15467c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg)
15477c478bd9Sstevel@tonic-gate {
15487c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
15497c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15527c478bd9Sstevel@tonic-gate "usb_pipe_drain_reqs: dip=0x%p ph_data=0x%p tm=%d uf=0x%x",
1553112116d8Sfb (void *)dip, (void *)ph_data, time, usb_flags);
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate if (ph_data == NULL) {
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE);
15587c478bd9Sstevel@tonic-gate }
15597c478bd9Sstevel@tonic-gate if (dip == NULL) {
15607c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
15617c478bd9Sstevel@tonic-gate
15627c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS);
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate
15657c478bd9Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
15667c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT);
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_drain_reqs,
15727c478bd9Sstevel@tonic-gate ph_impl, (usb_opaque_t)((uintptr_t)time), usb_flags, cb, cb_arg);
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
15757c478bd9Sstevel@tonic-gate }
15767c478bd9Sstevel@tonic-gate
15777c478bd9Sstevel@tonic-gate
15787c478bd9Sstevel@tonic-gate /*
15797c478bd9Sstevel@tonic-gate * usba_pipe_sync_drain_reqs
15807c478bd9Sstevel@tonic-gate * this function blocks until there are no more requests
15817c478bd9Sstevel@tonic-gate * owned by this dip on the pipe
15827c478bd9Sstevel@tonic-gate *
15837c478bd9Sstevel@tonic-gate * Arguments:
15847c478bd9Sstevel@tonic-gate * dip - devinfo pointer
15857c478bd9Sstevel@tonic-gate * ph_impl - pipe impl handle
15867c478bd9Sstevel@tonic-gate * timeout - timeout in seconds
15877c478bd9Sstevel@tonic-gate * Returns:
15887c478bd9Sstevel@tonic-gate * USB_SUCCESS - pipe successfully reset or request queued
15897c478bd9Sstevel@tonic-gate * USB_FAILURE - timeout
15907c478bd9Sstevel@tonic-gate * USB_* - see usbai.h
15917c478bd9Sstevel@tonic-gate */
15927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15937c478bd9Sstevel@tonic-gate int
usba_pipe_sync_drain_reqs(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t usb_flags)15947c478bd9Sstevel@tonic-gate usba_pipe_sync_drain_reqs(dev_info_t *dip,
15957c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
15967c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request,
15977c478bd9Sstevel@tonic-gate usb_flags_t usb_flags)
15987c478bd9Sstevel@tonic-gate {
15997c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1600112116d8Sfb ph_impl);
16017c478bd9Sstevel@tonic-gate int i;
16027c478bd9Sstevel@tonic-gate int timeout = 100 * (int)((uintptr_t)(request->arg));
16037c478bd9Sstevel@tonic-gate /* delay will be 10 ms */
16047c478bd9Sstevel@tonic-gate
16057c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
16067c478bd9Sstevel@tonic-gate
16077c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16087c478bd9Sstevel@tonic-gate "usba_pipe_sync_drain_reqs: "
16097c478bd9Sstevel@tonic-gate "dip=0x%p ph_data=0x%p timeout=%d ref=%d req=%d",
1610112116d8Sfb (void *)dip, (void *)ph_data, timeout,
1611112116d8Sfb usba_get_ph_ref_count(ph_data),
16127c478bd9Sstevel@tonic-gate ph_data->p_req_count);
16137c478bd9Sstevel@tonic-gate
16147c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate * for default pipe, we need to check the active request
16187c478bd9Sstevel@tonic-gate * and the queue
16197c478bd9Sstevel@tonic-gate * Note that a pipe reset on the default pipe doesn't flush
16207c478bd9Sstevel@tonic-gate * the queue
16217c478bd9Sstevel@tonic-gate * for all other pipes we just check ref and req count since
16227c478bd9Sstevel@tonic-gate * these pipes are unshared
16237c478bd9Sstevel@tonic-gate */
16247c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) {
16257c478bd9Sstevel@tonic-gate for (i = 0; (i < timeout) || (request->arg == 0); i++) {
16267c478bd9Sstevel@tonic-gate usba_list_entry_t *next, *tmpnext;
16277c478bd9Sstevel@tonic-gate usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)
1628112116d8Sfb ph_data->p_active_cntrl_req_wrp;
16297c478bd9Sstevel@tonic-gate int found = 0;
16307c478bd9Sstevel@tonic-gate int count = 0;
16317c478bd9Sstevel@tonic-gate
16327c478bd9Sstevel@tonic-gate /* active_req_wrp is only for control pipes */
16337c478bd9Sstevel@tonic-gate if ((req_wrp == NULL) || (req_wrp->wr_dip != dip)) {
16347c478bd9Sstevel@tonic-gate /* walk the queue */
16357c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_queue.list_mutex);
16367c478bd9Sstevel@tonic-gate next = ph_data->p_queue.next;
16377c478bd9Sstevel@tonic-gate while (next != NULL) {
16387c478bd9Sstevel@tonic-gate mutex_enter(&next->list_mutex);
16397c478bd9Sstevel@tonic-gate req_wrp = (usba_req_wrapper_t *)
1640112116d8Sfb next->private;
16417c478bd9Sstevel@tonic-gate found = (req_wrp->wr_dip == dip);
16427c478bd9Sstevel@tonic-gate if (found) {
16437c478bd9Sstevel@tonic-gate mutex_exit(&next->list_mutex);
16447c478bd9Sstevel@tonic-gate
16457c478bd9Sstevel@tonic-gate break;
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate tmpnext = next->next;
16487c478bd9Sstevel@tonic-gate mutex_exit(&next->list_mutex);
16497c478bd9Sstevel@tonic-gate next = tmpnext;
16507c478bd9Sstevel@tonic-gate count++;
16517c478bd9Sstevel@tonic-gate }
16527c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_queue.list_mutex);
16537c478bd9Sstevel@tonic-gate if (found == 0) {
16547c478bd9Sstevel@tonic-gate break;
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate }
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16597c478bd9Sstevel@tonic-gate "usb_pipe_sync_drain_reqs: "
16607c478bd9Sstevel@tonic-gate "cnt=%d active_req_wrp=0x%p",
1661112116d8Sfb count, (void *)ph_data->p_active_cntrl_req_wrp);
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
16647c478bd9Sstevel@tonic-gate delay(drv_usectohz(10000));
16657c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
16667c478bd9Sstevel@tonic-gate }
16677c478bd9Sstevel@tonic-gate } else {
16687c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
16697c478bd9Sstevel@tonic-gate for (i = 0; (i < timeout) || (request->arg == 0); i++) {
16707c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
16717c478bd9Sstevel@tonic-gate if (ph_data->p_req_count ||
16727c478bd9Sstevel@tonic-gate (ph_data->p_ph_impl->usba_ph_ref_count > 1)) {
16737c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
16747c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
16757c478bd9Sstevel@tonic-gate delay(drv_usectohz(10000));
16767c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
16777c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
16787c478bd9Sstevel@tonic-gate } else {
16797c478bd9Sstevel@tonic-gate break;
16807c478bd9Sstevel@tonic-gate }
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate
16857c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16867c478bd9Sstevel@tonic-gate "usb_pipe_sync_drain_reqs: timeout=%d active_req_wrp=0x%p req=%d",
1687112116d8Sfb i, (void *)ph_data->p_active_cntrl_req_wrp, ph_data->p_req_count);
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
16907c478bd9Sstevel@tonic-gate
16917c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl);
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate return (i >= timeout ? USB_FAILURE : USB_SUCCESS);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate
16977c478bd9Sstevel@tonic-gate /*
16987c478bd9Sstevel@tonic-gate * usba_persistent_pipe_open
16997c478bd9Sstevel@tonic-gate * Open all the pipes marked persistent for this device
17007c478bd9Sstevel@tonic-gate */
17017c478bd9Sstevel@tonic-gate int
usba_persistent_pipe_open(usba_device_t * usba_device)17027c478bd9Sstevel@tonic-gate usba_persistent_pipe_open(usba_device_t *usba_device)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl;
17057c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle;
17067c478bd9Sstevel@tonic-gate int i;
17077c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS;
17087c478bd9Sstevel@tonic-gate
17097c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1710112116d8Sfb "usba_persistent_pipe_open: usba_device=0x%p", (void *)usba_device);
17117c478bd9Sstevel@tonic-gate
17127c478bd9Sstevel@tonic-gate if (usba_device != NULL) {
17137c478bd9Sstevel@tonic-gate /* default pipe is the first one to be opened */
17147c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
17157c478bd9Sstevel@tonic-gate for (i = 0; (rval == USB_SUCCESS) &&
17167c478bd9Sstevel@tonic-gate (i < USBA_N_ENDPOINTS); i++) {
17177c478bd9Sstevel@tonic-gate
17187c478bd9Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[i];
17197c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
17207c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_flags & USBA_PH_DATA_PERSISTENT) {
17217c478bd9Sstevel@tonic-gate ph_impl->usba_ph_flags &=
1722112116d8Sfb ~USBA_PH_DATA_PERSISTENT;
17237c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
17247c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
17257c478bd9Sstevel@tonic-gate
17267c478bd9Sstevel@tonic-gate rval = usb_pipe_open(ph_impl->usba_ph_dip,
17277c478bd9Sstevel@tonic-gate &ph_impl->usba_ph_ep,
17287c478bd9Sstevel@tonic-gate &ph_impl->usba_ph_policy,
17297c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
17307c478bd9Sstevel@tonic-gate &pipe_handle);
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI,
17337c478bd9Sstevel@tonic-gate usbai_log_handle,
17347c478bd9Sstevel@tonic-gate "usba_persistent_pipe_open: "
17357c478bd9Sstevel@tonic-gate "ep_index=%d, rval=%d", i, rval);
17367c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
17377c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
17387c478bd9Sstevel@tonic-gate }
17397c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate
17447c478bd9Sstevel@tonic-gate return (rval);
17457c478bd9Sstevel@tonic-gate }
17467c478bd9Sstevel@tonic-gate
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate /*
17497c478bd9Sstevel@tonic-gate * usba_persistent_pipe_close
17507c478bd9Sstevel@tonic-gate * Close all pipes of this device and mark them persistent
17517c478bd9Sstevel@tonic-gate */
17527c478bd9Sstevel@tonic-gate void
usba_persistent_pipe_close(usba_device_t * usba_device)17537c478bd9Sstevel@tonic-gate usba_persistent_pipe_close(usba_device_t *usba_device)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl;
17567c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle;
17577c478bd9Sstevel@tonic-gate int i;
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1760112116d8Sfb "usba_persistent_pipe_close: usba_device=0x%p",
1761112116d8Sfb (void *)usba_device);
17627c478bd9Sstevel@tonic-gate
17637c478bd9Sstevel@tonic-gate if (usba_device != NULL) {
17647c478bd9Sstevel@tonic-gate /* default pipe is the last one to be closed */
17657c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
17667c478bd9Sstevel@tonic-gate
17677c478bd9Sstevel@tonic-gate for (i = (USBA_N_ENDPOINTS - 1); i >= 0; i--) {
17687c478bd9Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[i];
17697c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_data != NULL) {
17707c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
17717c478bd9Sstevel@tonic-gate ph_impl->usba_ph_flags |=
1772112116d8Sfb USBA_PH_DATA_PERSISTENT;
17737c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
17747c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate pipe_handle = (usb_pipe_handle_t)ph_impl;
17777c478bd9Sstevel@tonic-gate
17787c478bd9Sstevel@tonic-gate usb_pipe_close(ph_impl->usba_ph_dip,
17797c478bd9Sstevel@tonic-gate pipe_handle,
17807c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
17817c478bd9Sstevel@tonic-gate NULL, NULL);
17827c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex);
17837c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_data == NULL);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate }
17867c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex);
17877c478bd9Sstevel@tonic-gate }
17887c478bd9Sstevel@tonic-gate }
1789