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*993e3fafSRobert Mustacchi * Copyright 2016 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 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 * 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 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 * 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 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 * 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 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 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 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 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 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 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 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 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, 434*993e3fafSRobert 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 { 438*993e3fafSRobert 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 517*993e3fafSRobert Mustacchi /* 518*993e3fafSRobert Mustacchi * In the future, when we may have different versions of the extended 519*993e3fafSRobert Mustacchi * endpoint descriptor, they should be normalized to the current version 520*993e3fafSRobert Mustacchi * here such that all of the HCI drivers have a consistent view of the 521*993e3fafSRobert Mustacchi * world. The extended descriptor may be NULL if we are opening the 522*993e3fafSRobert Mustacchi * default control endpoint; however, we create a uniform view for the 523*993e3fafSRobert Mustacchi * HCI drivers. 524*993e3fafSRobert Mustacchi */ 525*993e3fafSRobert Mustacchi if (ep_xdescr == NULL) { 526*993e3fafSRobert Mustacchi bzero(&xep, sizeof (usb_ep_xdescr_t)); 527*993e3fafSRobert Mustacchi xep.uex_version = USB_EP_XDESCR_CURRENT_VERSION; 528*993e3fafSRobert Mustacchi xep.uex_ep = *ep; 529*993e3fafSRobert Mustacchi ep_xdescr = &xep; 530*993e3fafSRobert Mustacchi } 531*993e3fafSRobert 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; 535*993e3fafSRobert 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 */ 5437c478bd9Sstevel@tonic-gate if ((ep == &usba_default_ep_descr) && usba_device) { 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 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 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 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 783*993e3fafSRobert Mustacchi usb_pipe_xopen( 7847c478bd9Sstevel@tonic-gate dev_info_t *dip, 785*993e3fafSRobert 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 { 790*993e3fafSRobert 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" 801*993e3fafSRobert Mustacchi "dip=0x%p ep_xdesc=0x%p pp=0x%p uf=0x%x ph=0x%p", 802*993e3fafSRobert 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 810*993e3fafSRobert Mustacchi if ((ep_xdesc != NULL) && 811*993e3fafSRobert Mustacchi ((ep_xdesc->uex_version != USB_EP_XDESCR_CURRENT_VERSION) || 812*993e3fafSRobert Mustacchi ((ep_xdesc->uex_flags & ~USB_EP_XFLAGS_SS_COMP) != 0))) { 813*993e3fafSRobert Mustacchi 814*993e3fafSRobert Mustacchi return (USB_INVALID_ARGS); 815*993e3fafSRobert Mustacchi } 816*993e3fafSRobert 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 823*993e3fafSRobert Mustacchi /* 824*993e3fafSRobert Mustacchi * Check the device's speed. If we're being asked to open anything other 825*993e3fafSRobert Mustacchi * than the default endpoint and the device is superspeed or greater and 826*993e3fafSRobert Mustacchi * we only have a usb_ep_descr_t and not the full endpoint data, then 827*993e3fafSRobert Mustacchi * this was coming through usb_pipe_open() and we need to fail this 828*993e3fafSRobert Mustacchi * call. 829*993e3fafSRobert Mustacchi * 830*993e3fafSRobert Mustacchi * Some drivers technically cheat and open the default control endpoint 831*993e3fafSRobert Mustacchi * even though they're not supposed to. ugen appears to be the main 832*993e3fafSRobert Mustacchi * offender. To deal with this, we check to see if the endpoint 833*993e3fafSRobert Mustacchi * descriptor bcmps to our default and give them a break, since we don't 834*993e3fafSRobert Mustacchi * need extended info for default control endpoints. 835*993e3fafSRobert Mustacchi */ 836*993e3fafSRobert Mustacchi if (ep_xdesc != NULL && ep_xdesc->uex_flags == 0 && 837*993e3fafSRobert Mustacchi bcmp(&ep_xdesc->uex_ep, &usba_default_ep_descr, 838*993e3fafSRobert Mustacchi sizeof (usb_ep_descr_t)) != 0 && 839*993e3fafSRobert Mustacchi usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) { 840*993e3fafSRobert Mustacchi const char *dname = ddi_driver_name(dip); 841*993e3fafSRobert Mustacchi const char *prod, *mfg; 842*993e3fafSRobert Mustacchi 843*993e3fafSRobert Mustacchi prod = usba_device->usb_product_str; 844*993e3fafSRobert Mustacchi if (prod == NULL) 845*993e3fafSRobert Mustacchi prod = "Unknown Device"; 846*993e3fafSRobert Mustacchi mfg = usba_device->usb_mfg_str; 847*993e3fafSRobert Mustacchi if (mfg == NULL) 848*993e3fafSRobert Mustacchi mfg = "Unknown Manufacturer"; 849*993e3fafSRobert Mustacchi cmn_err(CE_NOTE, "driver %s attempting to open non-default " 850*993e3fafSRobert Mustacchi "of a USB 3.0 or newer device through usb_pipe_open(). " 851*993e3fafSRobert Mustacchi "%s must be updated to use usb_pipe_xopen() to work with " 852*993e3fafSRobert Mustacchi "USB device %s %s.", dname, dname, mfg, prod); 853*993e3fafSRobert Mustacchi return (USB_FAILURE); 854*993e3fafSRobert Mustacchi } 855*993e3fafSRobert Mustacchi 856*993e3fafSRobert 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? */ 864*993e3fafSRobert 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 */ 876*993e3fafSRobert 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; 886*993e3fafSRobert Mustacchi } else { 887*993e3fafSRobert 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, 943*993e3fafSRobert 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 975*993e3fafSRobert Mustacchi int 976*993e3fafSRobert Mustacchi usb_pipe_open( 977*993e3fafSRobert Mustacchi dev_info_t *dip, 978*993e3fafSRobert Mustacchi usb_ep_descr_t *ep, 979*993e3fafSRobert Mustacchi usb_pipe_policy_t *pipe_policy, 980*993e3fafSRobert Mustacchi usb_flags_t usb_flags, 981*993e3fafSRobert Mustacchi usb_pipe_handle_t *pipe_handle) 982*993e3fafSRobert Mustacchi { 983*993e3fafSRobert Mustacchi usb_ep_xdescr_t xdesc, *xp = NULL; 984*993e3fafSRobert Mustacchi 985*993e3fafSRobert Mustacchi /* 986*993e3fafSRobert Mustacchi * ep may be NULL if trying to open the default control endpoint. 987*993e3fafSRobert Mustacchi */ 988*993e3fafSRobert Mustacchi if (ep != NULL) { 989*993e3fafSRobert Mustacchi bzero(&xdesc, sizeof (usb_ep_xdescr_t)); 990*993e3fafSRobert Mustacchi xdesc.uex_version = USB_EP_XDESCR_CURRENT_VERSION; 991*993e3fafSRobert Mustacchi xdesc.uex_ep = *ep; 992*993e3fafSRobert Mustacchi xp = &xdesc; 993*993e3fafSRobert Mustacchi } 994*993e3fafSRobert Mustacchi 995*993e3fafSRobert Mustacchi return (usb_pipe_xopen(dip, xp, pipe_policy, usb_flags, 996*993e3fafSRobert Mustacchi pipe_handle)); 997*993e3fafSRobert 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 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 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 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 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 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 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 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 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 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 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 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