1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * USBA: Solaris USB Architecture support 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * all functions exposed to client drivers have prefix usb_ while all USBA 33*7c478bd9Sstevel@tonic-gate * internal functions or functions exposed to HCD or hubd only have prefix 34*7c478bd9Sstevel@tonic-gate * usba_ 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * this file contains all USBAI pipe management 37*7c478bd9Sstevel@tonic-gate * usb_pipe_open() 38*7c478bd9Sstevel@tonic-gate * usb_pipe_close() 39*7c478bd9Sstevel@tonic-gate * usb_pipe_set_private() 40*7c478bd9Sstevel@tonic-gate * usb_pipe_get_private() 41*7c478bd9Sstevel@tonic-gate * usb_pipe_abort() 42*7c478bd9Sstevel@tonic-gate * usb_pipe_reset() 43*7c478bd9Sstevel@tonic-gate * usb_pipe_drain_reqs() 44*7c478bd9Sstevel@tonic-gate */ 45*7c478bd9Sstevel@tonic-gate #define USBA_FRAMEWORK 46*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate extern pri_t maxclsyspri; 51*7c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* function prototypes */ 54*7c478bd9Sstevel@tonic-gate static void usba_pipe_do_async_func_thread(void *arg); 55*7c478bd9Sstevel@tonic-gate static int usba_pipe_sync_close(dev_info_t *, usba_ph_impl_t *, 56*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 57*7c478bd9Sstevel@tonic-gate static int usba_pipe_sync_abort(dev_info_t *, usba_ph_impl_t *, 58*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 59*7c478bd9Sstevel@tonic-gate static int usba_pipe_sync_reset(dev_info_t *, usba_ph_impl_t *, 60*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 61*7c478bd9Sstevel@tonic-gate static int usba_pipe_sync_drain_reqs(dev_info_t *, usba_ph_impl_t *, 62*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *, usb_flags_t); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* local tunables */ 65*7c478bd9Sstevel@tonic-gate static int usba_drain_timeout = 1000; /* in ms */ 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* return the default pipe for this device */ 68*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t 69*7c478bd9Sstevel@tonic-gate usba_get_dflt_pipe_handle(dev_info_t *dip) 70*7c478bd9Sstevel@tonic-gate { 71*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 72*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = NULL; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate if (dip) { 75*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 76*7c478bd9Sstevel@tonic-gate if (usba_device) { 77*7c478bd9Sstevel@tonic-gate pipe_handle = 78*7c478bd9Sstevel@tonic-gate (usb_pipe_handle_t)&usba_device->usb_ph_list[0]; 79*7c478bd9Sstevel@tonic-gate } 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate return (pipe_handle); 83*7c478bd9Sstevel@tonic-gate } 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* return dip owner of pipe_handle */ 87*7c478bd9Sstevel@tonic-gate dev_info_t * 88*7c478bd9Sstevel@tonic-gate usba_get_dip(usb_pipe_handle_t pipe_handle) 89*7c478bd9Sstevel@tonic-gate { 90*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle; 91*7c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate if (ph_impl) { 94*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 95*7c478bd9Sstevel@tonic-gate dip = ph_impl->usba_ph_dip; 96*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 97*7c478bd9Sstevel@tonic-gate } 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate return (dip); 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t 104*7c478bd9Sstevel@tonic-gate usba_usbdev_to_dflt_pipe_handle(usba_device_t *usba_device) 105*7c478bd9Sstevel@tonic-gate { 106*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = NULL; 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate if ((usba_device) && 109*7c478bd9Sstevel@tonic-gate (usba_device->usb_ph_list[0].usba_ph_data != NULL)) { 110*7c478bd9Sstevel@tonic-gate pipe_handle = (usb_pipe_handle_t)&usba_device->usb_ph_list[0]; 111*7c478bd9Sstevel@tonic-gate } 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate return (pipe_handle); 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t * 118*7c478bd9Sstevel@tonic-gate usba_get_ph_data(usb_pipe_handle_t pipe_handle) 119*7c478bd9Sstevel@tonic-gate { 120*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle; 121*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = NULL; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate if (ph_impl) { 124*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 125*7c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_ref_count >= 0); 126*7c478bd9Sstevel@tonic-gate ph_data = ph_impl->usba_ph_data; 127*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate return (ph_data); 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t 135*7c478bd9Sstevel@tonic-gate usba_get_pipe_handle(usba_pipe_handle_data_t *ph_data) 136*7c478bd9Sstevel@tonic-gate { 137*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph = NULL; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate if (ph_data) { 140*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 141*7c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0); 142*7c478bd9Sstevel@tonic-gate ph = (usb_pipe_handle_t)ph_data->p_ph_impl; 143*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate return (ph); 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * opaque to pipe handle impl translation with incr of ref count. The caller 152*7c478bd9Sstevel@tonic-gate * must release ph_data when done. Increment the ref count ensures that 153*7c478bd9Sstevel@tonic-gate * the ph_data will not be freed underneath us. 154*7c478bd9Sstevel@tonic-gate */ 155*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t * 156*7c478bd9Sstevel@tonic-gate usba_hold_ph_data(usb_pipe_handle_t pipe_handle) 157*7c478bd9Sstevel@tonic-gate { 158*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle; 159*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = NULL; 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate if (ph_impl) { 162*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate switch (ph_impl->usba_ph_state) { 165*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_IDLE: 166*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE: 167*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ERROR: 168*7c478bd9Sstevel@tonic-gate ph_data = ph_impl->usba_ph_data; 169*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count++; 170*7c478bd9Sstevel@tonic-gate break; 171*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSED: 172*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSING: 173*7c478bd9Sstevel@tonic-gate default: 174*7c478bd9Sstevel@tonic-gate break; 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 178*7c478bd9Sstevel@tonic-gate "usba_hold_ph_data: ph_impl=0x%p state=%d ref=%d", 179*7c478bd9Sstevel@tonic-gate ph_impl, ph_impl->usba_ph_state, 180*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count); 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate return (ph_data); 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate void 190*7c478bd9Sstevel@tonic-gate usba_release_ph_data(usba_ph_impl_t *ph_impl) 191*7c478bd9Sstevel@tonic-gate { 192*7c478bd9Sstevel@tonic-gate if (ph_impl) { 193*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 196*7c478bd9Sstevel@tonic-gate "usba_release_ph_data: " 197*7c478bd9Sstevel@tonic-gate "ph_impl=0x%p state=%d ref=%d", 198*7c478bd9Sstevel@tonic-gate ph_impl, ph_impl->usba_ph_state, 199*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count); 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate #ifndef __lock_lint 202*7c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_data) { 203*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 204*7c478bd9Sstevel@tonic-gate "usba_release_ph_data: req_count=%d", 205*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_data->p_req_count); 206*7c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_data->p_req_count >= 0); 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate #endif 209*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count--; 210*7c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_ref_count >= 0); 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * get pipe state from ph_data 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate usb_pipe_state_t 221*7c478bd9Sstevel@tonic-gate usba_get_ph_state(usba_pipe_handle_data_t *ph_data) 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 224*7c478bd9Sstevel@tonic-gate usb_pipe_state_t pipe_state; 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ph_data->p_mutex)); 227*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 228*7c478bd9Sstevel@tonic-gate pipe_state = ph_impl->usba_ph_state; 229*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate return (pipe_state); 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate /* 236*7c478bd9Sstevel@tonic-gate * get ref_count from ph_data 237*7c478bd9Sstevel@tonic-gate */ 238*7c478bd9Sstevel@tonic-gate int 239*7c478bd9Sstevel@tonic-gate usba_get_ph_ref_count(usba_pipe_handle_data_t *ph_data) 240*7c478bd9Sstevel@tonic-gate { 241*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 242*7c478bd9Sstevel@tonic-gate int ref_count; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 245*7c478bd9Sstevel@tonic-gate ref_count = ph_impl->usba_ph_ref_count; 246*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate return (ref_count); 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate /* 253*7c478bd9Sstevel@tonic-gate * new pipe state 254*7c478bd9Sstevel@tonic-gate * We need to hold both pipe mutex and ph_impl mutex 255*7c478bd9Sstevel@tonic-gate */ 256*7c478bd9Sstevel@tonic-gate void 257*7c478bd9Sstevel@tonic-gate usba_pipe_new_state(usba_pipe_handle_data_t *ph_data, usb_pipe_state_t state) 258*7c478bd9Sstevel@tonic-gate { 259*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ph_data->p_mutex)); 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 264*7c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0); 265*7c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_ref_count >= 0); 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 268*7c478bd9Sstevel@tonic-gate "usba_pipe_new_state: " 269*7c478bd9Sstevel@tonic-gate "ph_data=0x%p old=%s new=%s ref=%d req=%d", 270*7c478bd9Sstevel@tonic-gate ph_data, usb_str_pipe_state(ph_impl->usba_ph_state), 271*7c478bd9Sstevel@tonic-gate usb_str_pipe_state(state), 272*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count, ph_data->p_req_count); 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate switch (ph_impl->usba_ph_state) { 275*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_IDLE: 276*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE: 277*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_ERROR: 278*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSED: 279*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_state = state; 280*7c478bd9Sstevel@tonic-gate break; 281*7c478bd9Sstevel@tonic-gate case USB_PIPE_STATE_CLOSING: 282*7c478bd9Sstevel@tonic-gate default: 283*7c478bd9Sstevel@tonic-gate break; 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate /* 290*7c478bd9Sstevel@tonic-gate * async function execution support 291*7c478bd9Sstevel@tonic-gate * Arguments: 292*7c478bd9Sstevel@tonic-gate * dip - devinfo pointer 293*7c478bd9Sstevel@tonic-gate * sync_func - function to be executed 294*7c478bd9Sstevel@tonic-gate * ph_impl - impl pipehandle 295*7c478bd9Sstevel@tonic-gate * arg - opaque arg 296*7c478bd9Sstevel@tonic-gate * usb_flags - none 297*7c478bd9Sstevel@tonic-gate * callback - function to be called on completion, may be NULL 298*7c478bd9Sstevel@tonic-gate * callback_arg - argument for callback function 299*7c478bd9Sstevel@tonic-gate * 300*7c478bd9Sstevel@tonic-gate * Note: The caller must do a hold on ph_data 301*7c478bd9Sstevel@tonic-gate * We sleep for memory resources and taskq_dispatch which will ensure 302*7c478bd9Sstevel@tonic-gate * that this function succeeds 303*7c478bd9Sstevel@tonic-gate */ 304*7c478bd9Sstevel@tonic-gate int 305*7c478bd9Sstevel@tonic-gate usba_pipe_setup_func_call( 306*7c478bd9Sstevel@tonic-gate dev_info_t *dip, 307*7c478bd9Sstevel@tonic-gate int (*sync_func)(dev_info_t *, 308*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *, usba_pipe_async_req_t *, 309*7c478bd9Sstevel@tonic-gate usb_flags_t), 310*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 311*7c478bd9Sstevel@tonic-gate usb_opaque_t arg, 312*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 313*7c478bd9Sstevel@tonic-gate void (*callback)(usb_pipe_handle_t, 314*7c478bd9Sstevel@tonic-gate usb_opaque_t, int, usb_cb_flags_t), 315*7c478bd9Sstevel@tonic-gate usb_opaque_t callback_arg) 316*7c478bd9Sstevel@tonic-gate { 317*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request; 318*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl; 319*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data; 320*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 321*7c478bd9Sstevel@tonic-gate usb_cb_flags_t callback_flags; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, 324*7c478bd9Sstevel@tonic-gate "usba_pipe_setup_func_call: ph_impl=0x%p, func=0x%p", 325*7c478bd9Sstevel@tonic-gate ph_impl, sync_func); 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate if (((usb_flags & USB_FLAGS_SLEEP) == 0) && (callback == NULL)) { 328*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 329*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle, 330*7c478bd9Sstevel@tonic-gate "usba_pipe_setup_func_call: async request with " 331*7c478bd9Sstevel@tonic-gate "no callback"); 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate request = kmem_zalloc(sizeof (usba_pipe_async_req_t), KM_SLEEP); 337*7c478bd9Sstevel@tonic-gate request->dip = dip; 338*7c478bd9Sstevel@tonic-gate request->ph_impl = ph_impl; 339*7c478bd9Sstevel@tonic-gate request->arg = arg; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * OR in sleep flag. regardless of calling sync_func directly 343*7c478bd9Sstevel@tonic-gate * or in a new thread, we will always wait for completion 344*7c478bd9Sstevel@tonic-gate */ 345*7c478bd9Sstevel@tonic-gate request->usb_flags = usb_flags | USB_FLAGS_SLEEP; 346*7c478bd9Sstevel@tonic-gate request->sync_func = sync_func; 347*7c478bd9Sstevel@tonic-gate request->callback = callback; 348*7c478bd9Sstevel@tonic-gate request->callback_arg = callback_arg; 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate if (usb_flags & USB_FLAGS_SLEEP) { 351*7c478bd9Sstevel@tonic-gate rval = sync_func(dip, ph_impl, request, usb_flags); 352*7c478bd9Sstevel@tonic-gate kmem_free(request, sizeof (usba_pipe_async_req_t)); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate } else if (usba_async_ph_req(ph_data, 355*7c478bd9Sstevel@tonic-gate usba_pipe_do_async_func_thread, 356*7c478bd9Sstevel@tonic-gate (void *)request, USB_FLAGS_SLEEP) != USB_SUCCESS) { 357*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 358*7c478bd9Sstevel@tonic-gate "usb_async_req failed: ph_impl=0x%p, func=0x%p", 359*7c478bd9Sstevel@tonic-gate ph_impl, sync_func); 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate if (callback) { 362*7c478bd9Sstevel@tonic-gate callback_flags = 363*7c478bd9Sstevel@tonic-gate usba_check_intr_context(USB_CB_ASYNC_REQ_FAILED); 364*7c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, USB_FAILURE, 365*7c478bd9Sstevel@tonic-gate callback_flags); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate kmem_free(request, sizeof (usba_pipe_async_req_t)); 369*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate return (rval); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate /* 377*7c478bd9Sstevel@tonic-gate * taskq thread function to execute function synchronously 378*7c478bd9Sstevel@tonic-gate * Note: caller must have done a hold on ph_data 379*7c478bd9Sstevel@tonic-gate */ 380*7c478bd9Sstevel@tonic-gate static void 381*7c478bd9Sstevel@tonic-gate usba_pipe_do_async_func_thread(void *arg) 382*7c478bd9Sstevel@tonic-gate { 383*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request = (usba_pipe_async_req_t *)arg; 384*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = request->ph_impl; 385*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl; 386*7c478bd9Sstevel@tonic-gate int rval; 387*7c478bd9Sstevel@tonic-gate usb_cb_flags_t cb_flags = USB_CB_NO_INFO; 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate if ((rval = request->sync_func(request->dip, ph_impl, 390*7c478bd9Sstevel@tonic-gate request, request->usb_flags | USB_FLAGS_SLEEP)) != 391*7c478bd9Sstevel@tonic-gate USB_SUCCESS) { 392*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 393*7c478bd9Sstevel@tonic-gate "sync func failed (%d)", rval); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate if (request->callback) { 397*7c478bd9Sstevel@tonic-gate request->callback(pipe_handle, request->callback_arg, rval, 398*7c478bd9Sstevel@tonic-gate cb_flags); 399*7c478bd9Sstevel@tonic-gate } 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate kmem_free(request, sizeof (usba_pipe_async_req_t)); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate /* 406*7c478bd9Sstevel@tonic-gate * default endpoint descriptor and pipe policy 407*7c478bd9Sstevel@tonic-gate */ 408*7c478bd9Sstevel@tonic-gate usb_ep_descr_t usba_default_ep_descr = 409*7c478bd9Sstevel@tonic-gate {7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0}; 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* set some meaningful defaults */ 412*7c478bd9Sstevel@tonic-gate static usb_pipe_policy_t usba_default_ep_pipe_policy = {3}; 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate /* 416*7c478bd9Sstevel@tonic-gate * usb_get_ep_index: create an index from endpoint address that can 417*7c478bd9Sstevel@tonic-gate * be used to index into endpoint pipe lists 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate uchar_t 420*7c478bd9Sstevel@tonic-gate usb_get_ep_index(uint8_t ep_addr) 421*7c478bd9Sstevel@tonic-gate { 422*7c478bd9Sstevel@tonic-gate return ((ep_addr & USB_EP_NUM_MASK) + 423*7c478bd9Sstevel@tonic-gate ((ep_addr & USB_EP_DIR_MASK) ? 16 : 0)); 424*7c478bd9Sstevel@tonic-gate } 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * pipe management 429*7c478bd9Sstevel@tonic-gate * utility functions to init and destroy a pipehandle 430*7c478bd9Sstevel@tonic-gate */ 431*7c478bd9Sstevel@tonic-gate static int 432*7c478bd9Sstevel@tonic-gate usba_init_pipe_handle(dev_info_t *dip, 433*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device, 434*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep, 435*7c478bd9Sstevel@tonic-gate usb_pipe_policy_t *pipe_policy, 436*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl) 437*7c478bd9Sstevel@tonic-gate { 438*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 439*7c478bd9Sstevel@tonic-gate unsigned int def_instance = instance; 440*7c478bd9Sstevel@tonic-gate static unsigned int anon_instance = 0; 441*7c478bd9Sstevel@tonic-gate char tq_name[TASKQ_NAMELEN]; 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data; 444*7c478bd9Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie = 445*7c478bd9Sstevel@tonic-gate usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)-> 446*7c478bd9Sstevel@tonic-gate hcdi_iblock_cookie; 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 449*7c478bd9Sstevel@tonic-gate "usba_init_pipe_handle: " 450*7c478bd9Sstevel@tonic-gate "usba_device=0x%p ep=0x%x", usba_device, ep->bEndpointAddress); 451*7c478bd9Sstevel@tonic-gate mutex_init(&ph_data->p_mutex, NULL, MUTEX_DRIVER, iblock_cookie); 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate /* just to keep warlock happy, there is no contention yet */ 454*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 455*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate ASSERT(pipe_policy->pp_max_async_reqs); 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate if (instance != -1) { 460*7c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name), 461*7c478bd9Sstevel@tonic-gate "USB_%s_%x_pipehndl_tq_%d", 462*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress, instance); 463*7c478bd9Sstevel@tonic-gate } else { 464*7c478bd9Sstevel@tonic-gate def_instance = atomic_add_32_nv(&anon_instance, 1); 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name), 467*7c478bd9Sstevel@tonic-gate "USB_%s_%x_pipehndl_tq_%d_", 468*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress, def_instance); 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate ph_data->p_taskq = taskq_create(tq_name, 472*7c478bd9Sstevel@tonic-gate pipe_policy->pp_max_async_reqs + 1, 473*7c478bd9Sstevel@tonic-gate ((ep->bmAttributes & USB_EP_ATTR_MASK) == 474*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) ? 475*7c478bd9Sstevel@tonic-gate (maxclsyspri - 5) : minclsyspri, 476*7c478bd9Sstevel@tonic-gate 2 * (pipe_policy->pp_max_async_reqs + 1), 477*7c478bd9Sstevel@tonic-gate 8 * (pipe_policy->pp_max_async_reqs + 1), 478*7c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE); 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* 481*7c478bd9Sstevel@tonic-gate * Create a shared taskq. 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) { 484*7c478bd9Sstevel@tonic-gate int iface = usb_get_if_number(dip); 485*7c478bd9Sstevel@tonic-gate if (iface < 0) { 486*7c478bd9Sstevel@tonic-gate /* we own the device, use first entry */ 487*7c478bd9Sstevel@tonic-gate iface = 0; 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate if (instance != -1) { 491*7c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name), 492*7c478bd9Sstevel@tonic-gate "USB_%s_%x_shared_tq_%d", 493*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress, 494*7c478bd9Sstevel@tonic-gate instance); 495*7c478bd9Sstevel@tonic-gate } else { 496*7c478bd9Sstevel@tonic-gate (void) snprintf(tq_name, sizeof (tq_name), 497*7c478bd9Sstevel@tonic-gate "USB_%s_%x_shared_tq_%d_", 498*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ep->bEndpointAddress, 499*7c478bd9Sstevel@tonic-gate def_instance); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate if (usba_device->usb_shared_taskq_ref_count[iface] == 0) { 503*7c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq[iface] = 504*7c478bd9Sstevel@tonic-gate taskq_create(tq_name, 505*7c478bd9Sstevel@tonic-gate 1, /* Number threads. */ 506*7c478bd9Sstevel@tonic-gate maxclsyspri - 5, /* Priority */ 507*7c478bd9Sstevel@tonic-gate 1, /* minalloc */ 508*7c478bd9Sstevel@tonic-gate USBA_N_ENDPOINTS + 4, /* maxalloc */ 509*7c478bd9Sstevel@tonic-gate TASKQ_PREPOPULATE); 510*7c478bd9Sstevel@tonic-gate ASSERT(usba_device->usb_shared_taskq[iface] != NULL); 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq_ref_count[iface]++; 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate ph_data->p_dip = dip; 516*7c478bd9Sstevel@tonic-gate ph_data->p_usba_device = usba_device; 517*7c478bd9Sstevel@tonic-gate ph_data->p_ep = *ep; 518*7c478bd9Sstevel@tonic-gate ph_data->p_ph_impl = ph_impl; 519*7c478bd9Sstevel@tonic-gate if ((ep->bmAttributes & USB_EP_ATTR_MASK) == 520*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH) { 521*7c478bd9Sstevel@tonic-gate ph_data->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate /* fix up the MaxPacketSize if it is the default endpoint descr */ 525*7c478bd9Sstevel@tonic-gate if ((ep == &usba_default_ep_descr) && usba_device) { 526*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle, 527*7c478bd9Sstevel@tonic-gate "adjusting max packet size from %d to %d", 528*7c478bd9Sstevel@tonic-gate ph_data->p_ep.wMaxPacketSize, 529*7c478bd9Sstevel@tonic-gate usba_device->usb_dev_descr->bMaxPacketSize0); 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate ph_data->p_ep.wMaxPacketSize = usba_device->usb_dev_descr-> 532*7c478bd9Sstevel@tonic-gate bMaxPacketSize0; 533*7c478bd9Sstevel@tonic-gate } 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate /* now update usba_ph_impl structure */ 536*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 537*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_dip = dip; 538*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ep = ph_data->p_ep; 539*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_policy = ph_data->p_policy = *pipe_policy; 540*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate usba_init_list(&ph_data->p_queue, (usb_opaque_t)ph_data, iblock_cookie); 543*7c478bd9Sstevel@tonic-gate usba_init_list(&ph_data->p_cb_queue, (usb_opaque_t)ph_data, 544*7c478bd9Sstevel@tonic-gate iblock_cookie); 545*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 546*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate static void 553*7c478bd9Sstevel@tonic-gate usba_taskq_destroy(void *arg) 554*7c478bd9Sstevel@tonic-gate { 555*7c478bd9Sstevel@tonic-gate taskq_destroy((taskq_t *)arg); 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate static void 560*7c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(usba_pipe_handle_data_t *ph_data) 561*7c478bd9Sstevel@tonic-gate { 562*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 563*7c478bd9Sstevel@tonic-gate int timeout; 564*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 567*7c478bd9Sstevel@tonic-gate "usba_destroy_pipe_handle: ph_data=0x%p", ph_data); 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 570*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate /* check for all activity to drain */ 573*7c478bd9Sstevel@tonic-gate for (timeout = 0; timeout < usba_drain_timeout; timeout++) { 574*7c478bd9Sstevel@tonic-gate if ((ph_impl->usba_ph_ref_count <= 1) && 575*7c478bd9Sstevel@tonic-gate (ph_data->p_req_count == 0)) { 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate break; 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 580*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 581*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000)); 582*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 583*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate /* 587*7c478bd9Sstevel@tonic-gate * set state to closed here so any other thread 588*7c478bd9Sstevel@tonic-gate * that is waiting for the CLOSED state will 589*7c478bd9Sstevel@tonic-gate * continue. Otherwise, taskq_destroy might deadlock 590*7c478bd9Sstevel@tonic-gate */ 591*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_data = NULL; 592*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count = 0; 593*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSED; 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate if (ph_data->p_taskq) { 596*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 597*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 598*7c478bd9Sstevel@tonic-gate if (taskq_member(ph_data->p_taskq, curthread)) { 599*7c478bd9Sstevel@tonic-gate /* 600*7c478bd9Sstevel@tonic-gate * use system taskq to destroy ph's taskq to avoid 601*7c478bd9Sstevel@tonic-gate * deadlock 602*7c478bd9Sstevel@tonic-gate */ 603*7c478bd9Sstevel@tonic-gate (void) taskq_dispatch(system_taskq, 604*7c478bd9Sstevel@tonic-gate usba_taskq_destroy, ph_data->p_taskq, TQ_SLEEP); 605*7c478bd9Sstevel@tonic-gate } else { 606*7c478bd9Sstevel@tonic-gate taskq_destroy(ph_data->p_taskq); 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate } else { 609*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 610*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device; 614*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 615*7c478bd9Sstevel@tonic-gate if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) { 616*7c478bd9Sstevel@tonic-gate int iface = usb_get_if_number(ph_data->p_dip); 617*7c478bd9Sstevel@tonic-gate if (iface < 0) { 618*7c478bd9Sstevel@tonic-gate /* we own the device, use the first entry */ 619*7c478bd9Sstevel@tonic-gate iface = 0; 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 622*7c478bd9Sstevel@tonic-gate if (--usba_device->usb_shared_taskq_ref_count[iface] == 0) { 623*7c478bd9Sstevel@tonic-gate ph_data->p_spec_flag &= ~USBA_PH_FLAG_TQ_SHARE; 624*7c478bd9Sstevel@tonic-gate if (taskq_member(usba_device->usb_shared_taskq[iface], 625*7c478bd9Sstevel@tonic-gate curthread)) { 626*7c478bd9Sstevel@tonic-gate (void) taskq_dispatch( 627*7c478bd9Sstevel@tonic-gate system_taskq, 628*7c478bd9Sstevel@tonic-gate usba_taskq_destroy, 629*7c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq[iface], 630*7c478bd9Sstevel@tonic-gate TQ_SLEEP); 631*7c478bd9Sstevel@tonic-gate } else { 632*7c478bd9Sstevel@tonic-gate taskq_destroy( 633*7c478bd9Sstevel@tonic-gate usba_device->usb_shared_taskq[iface]); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 642*7c478bd9Sstevel@tonic-gate "usba_destroy_pipe_handle: destroying ph_data=0x%p", ph_data); 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate usba_destroy_list(&ph_data->p_queue); 645*7c478bd9Sstevel@tonic-gate usba_destroy_list(&ph_data->p_cb_queue); 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate /* destroy mutexes */ 648*7c478bd9Sstevel@tonic-gate mutex_destroy(&ph_data->p_mutex); 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate kmem_free(ph_data, sizeof (usba_pipe_handle_data_t)); 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate /* 655*7c478bd9Sstevel@tonic-gate * usba_drain_cbs: 656*7c478bd9Sstevel@tonic-gate * Drain the request callbacks on the pipe handle 657*7c478bd9Sstevel@tonic-gate */ 658*7c478bd9Sstevel@tonic-gate int 659*7c478bd9Sstevel@tonic-gate usba_drain_cbs(usba_pipe_handle_data_t *ph_data, usb_cb_flags_t cb_flags, 660*7c478bd9Sstevel@tonic-gate usb_cr_t cr) 661*7c478bd9Sstevel@tonic-gate { 662*7c478bd9Sstevel@tonic-gate usba_req_wrapper_t *req_wrp; 663*7c478bd9Sstevel@tonic-gate int flush_requests = 1; 664*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = ph_data->p_ph_impl; 665*7c478bd9Sstevel@tonic-gate int timeout; 666*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ph_data->p_mutex)); 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 671*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 672*7c478bd9Sstevel@tonic-gate "usba_drain_cbs: ph_data=0x%p ref=%d req=%d cb=0x%x cr=%d", 673*7c478bd9Sstevel@tonic-gate ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count, 674*7c478bd9Sstevel@tonic-gate cb_flags, cr); 675*7c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0); 676*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate if (ph_data->p_dip) { 679*7c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) { 680*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, 681*7c478bd9Sstevel@tonic-gate usbai_log_handle, 682*7c478bd9Sstevel@tonic-gate "no flushing on default pipe!"); 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate flush_requests = 0; 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate if (flush_requests) { 689*7c478bd9Sstevel@tonic-gate /* flush all requests in the pipehandle queue */ 690*7c478bd9Sstevel@tonic-gate while ((req_wrp = (usba_req_wrapper_t *) 691*7c478bd9Sstevel@tonic-gate usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) { 692*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 693*7c478bd9Sstevel@tonic-gate usba_do_req_exc_cb(req_wrp, cr, cb_flags); 694*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate /* 699*7c478bd9Sstevel@tonic-gate * wait for any callbacks in progress but don't wait for 700*7c478bd9Sstevel@tonic-gate * for queued requests on the default pipe 701*7c478bd9Sstevel@tonic-gate */ 702*7c478bd9Sstevel@tonic-gate for (timeout = 0; (timeout < usba_drain_timeout) && 703*7c478bd9Sstevel@tonic-gate (ph_data->p_req_count > 704*7c478bd9Sstevel@tonic-gate usba_list_entry_count(&ph_data->p_queue)); 705*7c478bd9Sstevel@tonic-gate timeout++) { 706*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 707*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000)); 708*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 709*7c478bd9Sstevel@tonic-gate } 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 712*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 713*7c478bd9Sstevel@tonic-gate "usba_drain_cbs done: ph_data=0x%p ref=%d req=%d", 714*7c478bd9Sstevel@tonic-gate ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count); 715*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate if (timeout == usba_drain_timeout) { 718*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 719*7c478bd9Sstevel@tonic-gate "draining callbacks timed out!"); 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate rval = USB_FAILURE; 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate return (rval); 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate /* 729*7c478bd9Sstevel@tonic-gate * usb_pipe_open(): 730*7c478bd9Sstevel@tonic-gate * 731*7c478bd9Sstevel@tonic-gate * Before using any pipe including the default pipe, it should be opened 732*7c478bd9Sstevel@tonic-gate * using usb_pipe_open(). On a successful open, a pipe handle is returned 733*7c478bd9Sstevel@tonic-gate * for use in other usb_pipe_*() functions 734*7c478bd9Sstevel@tonic-gate * 735*7c478bd9Sstevel@tonic-gate * The default pipe can only be opened by the hub driver 736*7c478bd9Sstevel@tonic-gate * 737*7c478bd9Sstevel@tonic-gate * The bandwidth has been allocated and guaranteed on successful 738*7c478bd9Sstevel@tonic-gate * opening of an isoc/intr pipes. 739*7c478bd9Sstevel@tonic-gate * 740*7c478bd9Sstevel@tonic-gate * Only the default pipe can be shared. all other control pipes 741*7c478bd9Sstevel@tonic-gate * are excusively opened by default. 742*7c478bd9Sstevel@tonic-gate * A pipe policy and endpoint descriptor must always be provided 743*7c478bd9Sstevel@tonic-gate * except for default pipe 744*7c478bd9Sstevel@tonic-gate * 745*7c478bd9Sstevel@tonic-gate * Arguments: 746*7c478bd9Sstevel@tonic-gate * dip - devinfo ptr 747*7c478bd9Sstevel@tonic-gate * ep - endpoint descriptor pointer 748*7c478bd9Sstevel@tonic-gate * pipe_policy - pointer to pipe policy which provides hints on how 749*7c478bd9Sstevel@tonic-gate * the pipe will be used. 750*7c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP wait for resources 751*7c478bd9Sstevel@tonic-gate * to become available 752*7c478bd9Sstevel@tonic-gate * pipe_handle - a pipe handle pointer. On a successful open, 753*7c478bd9Sstevel@tonic-gate * a pipe_handle is returned in this pointer. 754*7c478bd9Sstevel@tonic-gate * 755*7c478bd9Sstevel@tonic-gate * Return values: 756*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - open succeeded 757*7c478bd9Sstevel@tonic-gate * USB_FAILURE - unspecified open failure or pipe is already open 758*7c478bd9Sstevel@tonic-gate * USB_NO_RESOURCES - no resources were available to complete the open 759*7c478bd9Sstevel@tonic-gate * USB_NO_BANDWIDTH - no bandwidth available (isoc/intr pipes) 760*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 761*7c478bd9Sstevel@tonic-gate */ 762*7c478bd9Sstevel@tonic-gate int 763*7c478bd9Sstevel@tonic-gate usb_pipe_open( 764*7c478bd9Sstevel@tonic-gate dev_info_t *dip, 765*7c478bd9Sstevel@tonic-gate usb_ep_descr_t *ep, 766*7c478bd9Sstevel@tonic-gate usb_pipe_policy_t *pipe_policy, 767*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 768*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t *pipe_handle) 769*7c478bd9Sstevel@tonic-gate { 770*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 771*7c478bd9Sstevel@tonic-gate int rval; 772*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data; 773*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl; 774*7c478bd9Sstevel@tonic-gate uchar_t ep_index; 775*7c478bd9Sstevel@tonic-gate int kmflag; 776*7c478bd9Sstevel@tonic-gate size_t size; 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 779*7c478bd9Sstevel@tonic-gate "usb_pipe_open:\n\t" 780*7c478bd9Sstevel@tonic-gate "dip=0x%p ep=0x%p pp=0x%p uf=0x%x ph=0x%p", 781*7c478bd9Sstevel@tonic-gate dip, ep, pipe_policy, usb_flags, pipe_handle); 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (pipe_handle == NULL)) { 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) { 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 791*7c478bd9Sstevel@tonic-gate } 792*7c478bd9Sstevel@tonic-gate usba_device = usba_get_usba_device(dip); 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate if ((ep != NULL) && (pipe_policy == NULL)) { 795*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 796*7c478bd9Sstevel@tonic-gate "usb_pipe_open: null pipe policy"); 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 799*7c478bd9Sstevel@tonic-gate } 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate /* is the device still connected? */ 802*7c478bd9Sstevel@tonic-gate if ((ep != NULL) & DEVI_IS_DEVICE_REMOVED(dip)) { 803*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 804*7c478bd9Sstevel@tonic-gate "usb_pipe_open: device has been removed"); 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate return (USB_FAILURE); 807*7c478bd9Sstevel@tonic-gate } 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate /* 811*7c478bd9Sstevel@tonic-gate * if a null endpoint pointer was passed, use the default 812*7c478bd9Sstevel@tonic-gate * endpoint descriptor 813*7c478bd9Sstevel@tonic-gate */ 814*7c478bd9Sstevel@tonic-gate if (ep == NULL) { 815*7c478bd9Sstevel@tonic-gate if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) { 816*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 817*7c478bd9Sstevel@tonic-gate "usb_pipe_open: not allowed to open def pipe"); 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM); 820*7c478bd9Sstevel@tonic-gate } 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate ep = &usba_default_ep_descr; 823*7c478bd9Sstevel@tonic-gate pipe_policy = &usba_default_ep_pipe_policy; 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate if (usb_flags & USB_FLAGS_SERIALIZED_CB) { 827*7c478bd9Sstevel@tonic-gate if (((ep->bmAttributes & USB_EP_ATTR_MASK) == 828*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_CONTROL) || 829*7c478bd9Sstevel@tonic-gate ((ep->bmAttributes & USB_EP_ATTR_MASK) == 830*7c478bd9Sstevel@tonic-gate USB_EP_ATTR_ISOCH)) { 831*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 832*7c478bd9Sstevel@tonic-gate "usb_pipe_open: shared taskq not allowed with " 833*7c478bd9Sstevel@tonic-gate "ctrl or isoch pipe"); 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate kmflag = (usb_flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP; 840*7c478bd9Sstevel@tonic-gate size = sizeof (usba_pipe_handle_data_t); 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate if ((ph_data = kmem_zalloc(size, kmflag)) == NULL) { 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES); 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate /* check if pipe is already open and if so fail */ 848*7c478bd9Sstevel@tonic-gate ep_index = usb_get_ep_index(ep->bEndpointAddress); 849*7c478bd9Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[ep_index]; 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 852*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_data) { 855*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 856*7c478bd9Sstevel@tonic-gate "usb_pipe_open: pipe to ep %d already open", ep_index); 857*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 858*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 859*7c478bd9Sstevel@tonic-gate kmem_free(ph_data, size); 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate return (USB_BUSY); 862*7c478bd9Sstevel@tonic-gate } 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_data = ph_data; 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 867*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate if (usb_flags & USB_FLAGS_SERIALIZED_CB) { 870*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 871*7c478bd9Sstevel@tonic-gate ph_data->p_spec_flag |= USBA_PH_FLAG_TQ_SHARE; 872*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate /* 876*7c478bd9Sstevel@tonic-gate * allocate and initialize the pipe handle 877*7c478bd9Sstevel@tonic-gate */ 878*7c478bd9Sstevel@tonic-gate if ((rval = usba_init_pipe_handle(dip, usba_device, 879*7c478bd9Sstevel@tonic-gate ep, pipe_policy, ph_impl)) != USB_SUCCESS) { 880*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 881*7c478bd9Sstevel@tonic-gate "usb_pipe_open: pipe init failed (%d)", rval); 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate return (rval); 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate ph_data = ph_impl->usba_ph_data; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate /* 888*7c478bd9Sstevel@tonic-gate * ask the hcd to open the pipe 889*7c478bd9Sstevel@tonic-gate */ 890*7c478bd9Sstevel@tonic-gate if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_open(ph_data, 891*7c478bd9Sstevel@tonic-gate usb_flags)) != USB_SUCCESS) { 892*7c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(ph_data); 893*7c478bd9Sstevel@tonic-gate 894*7c478bd9Sstevel@tonic-gate *pipe_handle = NULL; 895*7c478bd9Sstevel@tonic-gate } else { 896*7c478bd9Sstevel@tonic-gate *pipe_handle = (usb_pipe_handle_t)ph_impl; 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate /* set the pipe state after a successful hcd open */ 899*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 900*7c478bd9Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 901*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 902*7c478bd9Sstevel@tonic-gate } 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 905*7c478bd9Sstevel@tonic-gate "usb_pipe_open: ph_impl=0x%p (0x%p)", ph_impl, ph_data); 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate return (rval); 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate /* 912*7c478bd9Sstevel@tonic-gate * usb_pipe_close/sync_close: 913*7c478bd9Sstevel@tonic-gate * 914*7c478bd9Sstevel@tonic-gate * Close a pipe and release all resources and free the pipe_handle. 915*7c478bd9Sstevel@tonic-gate * Automatic polling, if active, will be terminated 916*7c478bd9Sstevel@tonic-gate * 917*7c478bd9Sstevel@tonic-gate * Arguments: 918*7c478bd9Sstevel@tonic-gate * dip - devinfo ptr 919*7c478bd9Sstevel@tonic-gate * pipehandle - pointer to pipehandle. The pipehandle will be 920*7c478bd9Sstevel@tonic-gate * zeroed on successful completion 921*7c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 922*7c478bd9Sstevel@tonic-gate * wait for resources, pipe 923*7c478bd9Sstevel@tonic-gate * to become free, all callbacks completed 924*7c478bd9Sstevel@tonic-gate * callback - If USB_FLAGS_SLEEP has not been specified, a 925*7c478bd9Sstevel@tonic-gate * callback will be performed. 926*7c478bd9Sstevel@tonic-gate * callback_arg - the first argument of the callback. Note that 927*7c478bd9Sstevel@tonic-gate * the pipehandle will be zeroed and not passed 928*7c478bd9Sstevel@tonic-gate * 929*7c478bd9Sstevel@tonic-gate * Notes: 930*7c478bd9Sstevel@tonic-gate * Pipe close will always succeed regardless whether USB_FLAGS_SLEEP has been 931*7c478bd9Sstevel@tonic-gate * specified or not. 932*7c478bd9Sstevel@tonic-gate * An async close will always succeed if the hint in the pipe policy 933*7c478bd9Sstevel@tonic-gate * has been correct about the max number of async taskq requests required. 934*7c478bd9Sstevel@tonic-gate * If there are really no resources, the pipe handle will be linked into 935*7c478bd9Sstevel@tonic-gate * a garbage pipe list and periodically checked by USBA until it can be 936*7c478bd9Sstevel@tonic-gate * closed. This may cause a hang in the detach of the driver. 937*7c478bd9Sstevel@tonic-gate * USBA will prevent the client from submitting more requests to a pipe 938*7c478bd9Sstevel@tonic-gate * that is being closed 939*7c478bd9Sstevel@tonic-gate * Subsequent usb_pipe_close() requests on the same pipe to USBA will 940*7c478bd9Sstevel@tonic-gate * wait for the previous close(s) to finish. 941*7c478bd9Sstevel@tonic-gate * 942*7c478bd9Sstevel@tonic-gate * Note that once we start closing a pipe, we cannot go back anymore 943*7c478bd9Sstevel@tonic-gate * to a normal pipe state 944*7c478bd9Sstevel@tonic-gate */ 945*7c478bd9Sstevel@tonic-gate void 946*7c478bd9Sstevel@tonic-gate usb_pipe_close(dev_info_t *dip, 947*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle, 948*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 949*7c478bd9Sstevel@tonic-gate void (*callback)( 950*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle, 951*7c478bd9Sstevel@tonic-gate usb_opaque_t arg, 952*7c478bd9Sstevel@tonic-gate int rval, 953*7c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 954*7c478bd9Sstevel@tonic-gate usb_opaque_t callback_arg) 955*7c478bd9Sstevel@tonic-gate { 956*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data; 957*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle; 958*7c478bd9Sstevel@tonic-gate usb_cb_flags_t callback_flags; 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 961*7c478bd9Sstevel@tonic-gate "usb_pipe_close: ph=0x%p", pipe_handle); 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate callback_flags = usba_check_intr_context(USB_CB_NO_INFO); 964*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (pipe_handle == NULL)) { 965*7c478bd9Sstevel@tonic-gate if (callback) { 966*7c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, 967*7c478bd9Sstevel@tonic-gate USB_INVALID_ARGS, callback_flags); 968*7c478bd9Sstevel@tonic-gate } else { 969*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, 970*7c478bd9Sstevel@tonic-gate usbai_log_handle, 971*7c478bd9Sstevel@tonic-gate "usb_pipe_close: invalid arguments"); 972*7c478bd9Sstevel@tonic-gate } 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate return; 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) { 978*7c478bd9Sstevel@tonic-gate /* 979*7c478bd9Sstevel@tonic-gate * It is the client driver doing the pipe close, 980*7c478bd9Sstevel@tonic-gate * the pipe is no longer persistent then. 981*7c478bd9Sstevel@tonic-gate */ 982*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 983*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_flags &= ~USBA_PH_DATA_PERSISTENT; 984*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 985*7c478bd9Sstevel@tonic-gate } 986*7c478bd9Sstevel@tonic-gate 987*7c478bd9Sstevel@tonic-gate if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) { 988*7c478bd9Sstevel@tonic-gate if (callback) { 989*7c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, 990*7c478bd9Sstevel@tonic-gate USB_INVALID_CONTEXT, callback_flags); 991*7c478bd9Sstevel@tonic-gate } else { 992*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, 993*7c478bd9Sstevel@tonic-gate usbai_log_handle, 994*7c478bd9Sstevel@tonic-gate "usb_pipe_close: invalid context"); 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate return; 998*7c478bd9Sstevel@tonic-gate } 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) { 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate /* hold pipehandle anyways since we will decrement later */ 1003*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 1004*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_ref_count++; 1005*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close, 1008*7c478bd9Sstevel@tonic-gate ph_impl, NULL, usb_flags, callback, callback_arg); 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate return; 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate 1013*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data) && 1016*7c478bd9Sstevel@tonic-gate ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0)) { 1017*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle, 1018*7c478bd9Sstevel@tonic-gate "usb_pipe_close: not allowed to close def pipe"); 1019*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate if (callback) { 1024*7c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, 1025*7c478bd9Sstevel@tonic-gate USB_INVALID_PIPE, callback_flags); 1026*7c478bd9Sstevel@tonic-gate } else { 1027*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, 1028*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1029*7c478bd9Sstevel@tonic-gate "usb_pipe_close: invalid pipe"); 1030*7c478bd9Sstevel@tonic-gate } 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate return; 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1036*7c478bd9Sstevel@tonic-gate 1037*7c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close, 1038*7c478bd9Sstevel@tonic-gate ph_impl, NULL, usb_flags, callback, callback_arg); 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1043*7c478bd9Sstevel@tonic-gate static int 1044*7c478bd9Sstevel@tonic-gate usba_pipe_sync_close(dev_info_t *dip, usba_ph_impl_t *ph_impl, 1045*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, usb_flags_t usb_flags) 1046*7c478bd9Sstevel@tonic-gate { 1047*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 1048*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data( 1049*7c478bd9Sstevel@tonic-gate (usb_pipe_handle_t)ph_impl); 1050*7c478bd9Sstevel@tonic-gate int attribute; 1051*7c478bd9Sstevel@tonic-gate uchar_t dir; 1052*7c478bd9Sstevel@tonic-gate int timeout; 1053*7c478bd9Sstevel@tonic-gate 1054*7c478bd9Sstevel@tonic-gate if (ph_impl == NULL) { 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 1060*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1061*7c478bd9Sstevel@tonic-gate "usba_pipe_sync_close: dip=0x%p ph_data=0x%p state=%d ref=%d", 1062*7c478bd9Sstevel@tonic-gate dip, ph_data, ph_impl->usba_ph_state, ph_impl->usba_ph_ref_count); 1063*7c478bd9Sstevel@tonic-gate 1064*7c478bd9Sstevel@tonic-gate /* 1065*7c478bd9Sstevel@tonic-gate * if another thread opens the pipe again, this loop could 1066*7c478bd9Sstevel@tonic-gate * be truly forever 1067*7c478bd9Sstevel@tonic-gate */ 1068*7c478bd9Sstevel@tonic-gate if ((ph_data == NULL) || 1069*7c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSING) || 1070*7c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSED)) { 1071*7c478bd9Sstevel@tonic-gate /* wait forever till really closed */ 1072*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1073*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate while (usba_get_ph_data((usb_pipe_handle_t)ph_impl)) { 1076*7c478bd9Sstevel@tonic-gate delay(1); 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1080*7c478bd9Sstevel@tonic-gate } 1081*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSING; 1082*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1085*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 1086*7c478bd9Sstevel@tonic-gate 1087*7c478bd9Sstevel@tonic-gate attribute = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK; 1088*7c478bd9Sstevel@tonic-gate dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK; 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device; 1091*7c478bd9Sstevel@tonic-gate 1092*7c478bd9Sstevel@tonic-gate /* 1093*7c478bd9Sstevel@tonic-gate * For control and bulk, we will drain till ref_count <= 1 and 1094*7c478bd9Sstevel@tonic-gate * req_count == 0 but for isoc and intr IN, we can only wait 1095*7c478bd9Sstevel@tonic-gate * till the ref_count === 1 as the req_count will never go to 0 1096*7c478bd9Sstevel@tonic-gate */ 1097*7c478bd9Sstevel@tonic-gate for (timeout = 0; timeout < usba_drain_timeout; timeout++) { 1098*7c478bd9Sstevel@tonic-gate switch (attribute) { 1099*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL: 1100*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_BULK: 1101*7c478bd9Sstevel@tonic-gate if ((ph_data->p_req_count == 0) && 1102*7c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_ref_count <= 1)) { 1103*7c478bd9Sstevel@tonic-gate goto done; 1104*7c478bd9Sstevel@tonic-gate } 1105*7c478bd9Sstevel@tonic-gate break; 1106*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR: 1107*7c478bd9Sstevel@tonic-gate case USB_EP_ATTR_ISOCH: 1108*7c478bd9Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) { 1109*7c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_ref_count <= 1) { 1110*7c478bd9Sstevel@tonic-gate goto done; 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate } else if ((ph_data->p_req_count == 0) && 1113*7c478bd9Sstevel@tonic-gate (ph_impl->usba_ph_ref_count <= 1)) { 1114*7c478bd9Sstevel@tonic-gate goto done; 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate break; 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1119*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1120*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000)); 1121*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1122*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 1123*7c478bd9Sstevel@tonic-gate } 1124*7c478bd9Sstevel@tonic-gate done: 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1127*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate if (timeout >= usba_drain_timeout) { 1130*7c478bd9Sstevel@tonic-gate int draining_succeeded; 1131*7c478bd9Sstevel@tonic-gate 1132*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1133*7c478bd9Sstevel@tonic-gate "timeout on draining requests, resetting pipe 0x%p", 1134*7c478bd9Sstevel@tonic-gate ph_impl); 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data, 1137*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP); 1138*7c478bd9Sstevel@tonic-gate 1139*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1140*7c478bd9Sstevel@tonic-gate draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE, 1141*7c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET); 1142*7c478bd9Sstevel@tonic-gate /* this MUST have succeeded */ 1143*7c478bd9Sstevel@tonic-gate ASSERT(draining_succeeded == USB_SUCCESS); 1144*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle, 1147*7c478bd9Sstevel@tonic-gate "draining requests done"); 1148*7c478bd9Sstevel@tonic-gate } 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate if (usba_device->usb_hcdi_ops->usba_hcdi_pipe_close(ph_data, 1151*7c478bd9Sstevel@tonic-gate usb_flags) != USB_SUCCESS) { 1152*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle, 1153*7c478bd9Sstevel@tonic-gate "usba_pipe_sync_close: hcd close failed"); 1154*7c478bd9Sstevel@tonic-gate /* carry on regardless! */ 1155*7c478bd9Sstevel@tonic-gate } 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate usba_destroy_pipe_handle(ph_data); 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1160*7c478bd9Sstevel@tonic-gate } 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate /* 1164*7c478bd9Sstevel@tonic-gate * usb_pipe_set_private: 1165*7c478bd9Sstevel@tonic-gate * set private client date in the pipe handle 1166*7c478bd9Sstevel@tonic-gate */ 1167*7c478bd9Sstevel@tonic-gate int 1168*7c478bd9Sstevel@tonic-gate usb_pipe_set_private(usb_pipe_handle_t pipe_handle, usb_opaque_t data) 1169*7c478bd9Sstevel@tonic-gate { 1170*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1173*7c478bd9Sstevel@tonic-gate "usb_pipe_set_private: "); 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 1176*7c478bd9Sstevel@tonic-gate 1177*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 1178*7c478bd9Sstevel@tonic-gate } 1179*7c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) { 1180*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 1181*7c478bd9Sstevel@tonic-gate 1182*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PERM); 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1186*7c478bd9Sstevel@tonic-gate ph_data->p_client_private = data; 1187*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 1190*7c478bd9Sstevel@tonic-gate 1191*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1192*7c478bd9Sstevel@tonic-gate } 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate /* 1196*7c478bd9Sstevel@tonic-gate * usb_pipe_get_private: 1197*7c478bd9Sstevel@tonic-gate * get private client date from the pipe handle 1198*7c478bd9Sstevel@tonic-gate */ 1199*7c478bd9Sstevel@tonic-gate usb_opaque_t 1200*7c478bd9Sstevel@tonic-gate usb_pipe_get_private(usb_pipe_handle_t pipe_handle) 1201*7c478bd9Sstevel@tonic-gate { 1202*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1203*7c478bd9Sstevel@tonic-gate usb_opaque_t data; 1204*7c478bd9Sstevel@tonic-gate 1205*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1206*7c478bd9Sstevel@tonic-gate "usb_pipe_get_private:"); 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate return (NULL); 1211*7c478bd9Sstevel@tonic-gate } 1212*7c478bd9Sstevel@tonic-gate 1213*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1214*7c478bd9Sstevel@tonic-gate data = ph_data->p_client_private; 1215*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1216*7c478bd9Sstevel@tonic-gate 1217*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl); 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate return (data); 1220*7c478bd9Sstevel@tonic-gate } 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate /* 1224*7c478bd9Sstevel@tonic-gate * usb_pipe_reset 1225*7c478bd9Sstevel@tonic-gate * Arguments: 1226*7c478bd9Sstevel@tonic-gate * dip - devinfo pointer 1227*7c478bd9Sstevel@tonic-gate * pipe_handle - opaque pipe handle 1228*7c478bd9Sstevel@tonic-gate * Returns: 1229*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - pipe successfully reset or request queued 1230*7c478bd9Sstevel@tonic-gate * USB_FAILURE - undetermined failure 1231*7c478bd9Sstevel@tonic-gate * USB_INVALID_PIPE - pipe is invalid or already closed 1232*7c478bd9Sstevel@tonic-gate */ 1233*7c478bd9Sstevel@tonic-gate void 1234*7c478bd9Sstevel@tonic-gate usb_pipe_reset(dev_info_t *dip, 1235*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle, 1236*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 1237*7c478bd9Sstevel@tonic-gate void (*callback)( 1238*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 1239*7c478bd9Sstevel@tonic-gate usb_opaque_t arg, 1240*7c478bd9Sstevel@tonic-gate int rval, 1241*7c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 1242*7c478bd9Sstevel@tonic-gate usb_opaque_t callback_arg) 1243*7c478bd9Sstevel@tonic-gate { 1244*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle; 1245*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1246*7c478bd9Sstevel@tonic-gate usb_cb_flags_t callback_flags; 1247*7c478bd9Sstevel@tonic-gate 1248*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1249*7c478bd9Sstevel@tonic-gate "usb_pipe_reset: dip=0x%p ph=0x%p uf=0x%x", 1250*7c478bd9Sstevel@tonic-gate dip, pipe_handle, usb_flags); 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate callback_flags = usba_check_intr_context(USB_CB_NO_INFO); 1253*7c478bd9Sstevel@tonic-gate 1254*7c478bd9Sstevel@tonic-gate if ((dip == NULL) || (ph_data == NULL)) { 1255*7c478bd9Sstevel@tonic-gate if (callback) { 1256*7c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, 1257*7c478bd9Sstevel@tonic-gate USB_INVALID_ARGS, callback_flags); 1258*7c478bd9Sstevel@tonic-gate } else { 1259*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, 1260*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1261*7c478bd9Sstevel@tonic-gate "usb_pipe_reset: invalid arguments"); 1262*7c478bd9Sstevel@tonic-gate } 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1265*7c478bd9Sstevel@tonic-gate 1266*7c478bd9Sstevel@tonic-gate return; 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) { 1269*7c478bd9Sstevel@tonic-gate if (callback) { 1270*7c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, 1271*7c478bd9Sstevel@tonic-gate USB_INVALID_CONTEXT, callback_flags); 1272*7c478bd9Sstevel@tonic-gate } else { 1273*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, 1274*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1275*7c478bd9Sstevel@tonic-gate "usb_pipe_reset: invalid context"); 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate return; 1281*7c478bd9Sstevel@tonic-gate } 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate /* is this the default pipe? */ 1286*7c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) { 1287*7c478bd9Sstevel@tonic-gate if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) { 1288*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, usbai_log_handle, 1289*7c478bd9Sstevel@tonic-gate "usb_pipe_reset: not allowed to reset def pipe"); 1290*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate if (callback) { 1293*7c478bd9Sstevel@tonic-gate callback(pipe_handle, callback_arg, 1294*7c478bd9Sstevel@tonic-gate USB_INVALID_PIPE, callback_flags); 1295*7c478bd9Sstevel@tonic-gate } else { 1296*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L1(DPRINT_MASK_USBAI, 1297*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1298*7c478bd9Sstevel@tonic-gate "usb_pipe_reset: invalid pipe"); 1299*7c478bd9Sstevel@tonic-gate } 1300*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate return; 1303*7c478bd9Sstevel@tonic-gate } 1304*7c478bd9Sstevel@tonic-gate } 1305*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip, 1308*7c478bd9Sstevel@tonic-gate usba_pipe_sync_reset, ph_impl, NULL, usb_flags, callback, 1309*7c478bd9Sstevel@tonic-gate callback_arg); 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1314*7c478bd9Sstevel@tonic-gate int 1315*7c478bd9Sstevel@tonic-gate usba_pipe_sync_reset(dev_info_t *dip, 1316*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 1317*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, 1318*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 1319*7c478bd9Sstevel@tonic-gate { 1320*7c478bd9Sstevel@tonic-gate int rval, draining_succeeded; 1321*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t) 1322*7c478bd9Sstevel@tonic-gate ph_impl); 1323*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 1324*7c478bd9Sstevel@tonic-gate 1325*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1326*7c478bd9Sstevel@tonic-gate "usba_pipe_sync_reset: dip=0x%p ph_data=0x%p uf=0x%x", 1327*7c478bd9Sstevel@tonic-gate dip, ph_data, usb_flags); 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1330*7c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device; 1331*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data, 1334*7c478bd9Sstevel@tonic-gate usb_flags); 1335*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate /* 1338*7c478bd9Sstevel@tonic-gate * The host controller has stopped polling of the endpoint. 1339*7c478bd9Sstevel@tonic-gate */ 1340*7c478bd9Sstevel@tonic-gate draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE, 1341*7c478bd9Sstevel@tonic-gate USB_CR_PIPE_RESET); 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate /* this MUST have succeeded */ 1344*7c478bd9Sstevel@tonic-gate ASSERT(draining_succeeded == USB_SUCCESS); 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 1347*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate /* 1350*7c478bd9Sstevel@tonic-gate * if there are requests still queued on the default pipe, 1351*7c478bd9Sstevel@tonic-gate * start them now 1352*7c478bd9Sstevel@tonic-gate */ 1353*7c478bd9Sstevel@tonic-gate usba_start_next_req(ph_data); 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1356*7c478bd9Sstevel@tonic-gate 1357*7c478bd9Sstevel@tonic-gate return (rval); 1358*7c478bd9Sstevel@tonic-gate } 1359*7c478bd9Sstevel@tonic-gate 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate /* 1362*7c478bd9Sstevel@tonic-gate * usba_pipe_clear: 1363*7c478bd9Sstevel@tonic-gate * call hcd to clear pipe but don't wait for draining 1364*7c478bd9Sstevel@tonic-gate */ 1365*7c478bd9Sstevel@tonic-gate void 1366*7c478bd9Sstevel@tonic-gate usba_pipe_clear(usb_pipe_handle_t pipe_handle) 1367*7c478bd9Sstevel@tonic-gate { 1368*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data(pipe_handle); 1369*7c478bd9Sstevel@tonic-gate usba_device_t *usba_device; 1370*7c478bd9Sstevel@tonic-gate usba_req_wrapper_t *req_wrp; 1371*7c478bd9Sstevel@tonic-gate int flush_requests = 1; 1372*7c478bd9Sstevel@tonic-gate 1373*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1374*7c478bd9Sstevel@tonic-gate "usba_pipe_clear: ph_data=0x%p", ph_data); 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate return; 1379*7c478bd9Sstevel@tonic-gate } 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1382*7c478bd9Sstevel@tonic-gate if (USBA_PIPE_CLOSING(usba_get_ph_state(ph_data))) { 1383*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1384*7c478bd9Sstevel@tonic-gate 1385*7c478bd9Sstevel@tonic-gate return; 1386*7c478bd9Sstevel@tonic-gate } 1387*7c478bd9Sstevel@tonic-gate usba_device = ph_data->p_usba_device; 1388*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1389*7c478bd9Sstevel@tonic-gate 1390*7c478bd9Sstevel@tonic-gate (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data, 1391*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP); 1392*7c478bd9Sstevel@tonic-gate 1393*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1394*7c478bd9Sstevel@tonic-gate if (ph_data->p_dip) { 1395*7c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) { 1396*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, 1397*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1398*7c478bd9Sstevel@tonic-gate "no flushing on default pipe!"); 1399*7c478bd9Sstevel@tonic-gate 1400*7c478bd9Sstevel@tonic-gate flush_requests = 0; 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate } 1403*7c478bd9Sstevel@tonic-gate 1404*7c478bd9Sstevel@tonic-gate if (flush_requests) { 1405*7c478bd9Sstevel@tonic-gate /* flush all requests in the pipehandle queue */ 1406*7c478bd9Sstevel@tonic-gate while ((req_wrp = (usba_req_wrapper_t *) 1407*7c478bd9Sstevel@tonic-gate usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) { 1408*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1409*7c478bd9Sstevel@tonic-gate usba_do_req_exc_cb(req_wrp, USB_CR_FLUSHED, 1410*7c478bd9Sstevel@tonic-gate USB_CB_RESET_PIPE); 1411*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate } 1414*7c478bd9Sstevel@tonic-gate 1415*7c478bd9Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE); 1416*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1417*7c478bd9Sstevel@tonic-gate } 1418*7c478bd9Sstevel@tonic-gate 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate /* 1421*7c478bd9Sstevel@tonic-gate * 1422*7c478bd9Sstevel@tonic-gate * usb_pipe_drain_reqs 1423*7c478bd9Sstevel@tonic-gate * this function blocks until there are no more requests 1424*7c478bd9Sstevel@tonic-gate * owned by this dip on the pipe 1425*7c478bd9Sstevel@tonic-gate * 1426*7c478bd9Sstevel@tonic-gate * Arguments: 1427*7c478bd9Sstevel@tonic-gate * dip - devinfo pointer 1428*7c478bd9Sstevel@tonic-gate * pipe_handle - opaque pipe handle 1429*7c478bd9Sstevel@tonic-gate * timeout - timeout in seconds 1430*7c478bd9Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: 1431*7c478bd9Sstevel@tonic-gate * wait for completion. 1432*7c478bd9Sstevel@tonic-gate * cb - if USB_FLAGS_SLEEP has not been specified 1433*7c478bd9Sstevel@tonic-gate * this callback function will be called on 1434*7c478bd9Sstevel@tonic-gate * completion. This callback may be NULL 1435*7c478bd9Sstevel@tonic-gate * and no notification of completion will then 1436*7c478bd9Sstevel@tonic-gate * be provided. 1437*7c478bd9Sstevel@tonic-gate * cb_arg - 2nd argument to callback function. 1438*7c478bd9Sstevel@tonic-gate * 1439*7c478bd9Sstevel@tonic-gate * callback and callback_arg should be NULL if USB_FLAGS_SLEEP has 1440*7c478bd9Sstevel@tonic-gate * been specified 1441*7c478bd9Sstevel@tonic-gate * 1442*7c478bd9Sstevel@tonic-gate * Returns: 1443*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - pipe successfully reset or request queued 1444*7c478bd9Sstevel@tonic-gate * USB_FAILURE - timeout 1445*7c478bd9Sstevel@tonic-gate * USB_* - refer to usbai.h 1446*7c478bd9Sstevel@tonic-gate */ 1447*7c478bd9Sstevel@tonic-gate int 1448*7c478bd9Sstevel@tonic-gate usb_pipe_drain_reqs(dev_info_t *dip, 1449*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle, 1450*7c478bd9Sstevel@tonic-gate uint_t time, 1451*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags, 1452*7c478bd9Sstevel@tonic-gate void (*cb)( 1453*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t ph, 1454*7c478bd9Sstevel@tonic-gate usb_opaque_t arg, /* cb arg */ 1455*7c478bd9Sstevel@tonic-gate int rval, 1456*7c478bd9Sstevel@tonic-gate usb_cb_flags_t flags), 1457*7c478bd9Sstevel@tonic-gate usb_opaque_t cb_arg) 1458*7c478bd9Sstevel@tonic-gate { 1459*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle; 1460*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle); 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1463*7c478bd9Sstevel@tonic-gate "usb_pipe_drain_reqs: dip=0x%p ph_data=0x%p tm=%d uf=0x%x", 1464*7c478bd9Sstevel@tonic-gate dip, ph_data, time, usb_flags); 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate if (ph_data == NULL) { 1467*7c478bd9Sstevel@tonic-gate 1468*7c478bd9Sstevel@tonic-gate return (USB_INVALID_PIPE); 1469*7c478bd9Sstevel@tonic-gate } 1470*7c478bd9Sstevel@tonic-gate if (dip == NULL) { 1471*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate return (USB_INVALID_ARGS); 1474*7c478bd9Sstevel@tonic-gate } 1475*7c478bd9Sstevel@tonic-gate 1476*7c478bd9Sstevel@tonic-gate if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) { 1477*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1478*7c478bd9Sstevel@tonic-gate 1479*7c478bd9Sstevel@tonic-gate return (USB_INVALID_CONTEXT); 1480*7c478bd9Sstevel@tonic-gate } 1481*7c478bd9Sstevel@tonic-gate 1482*7c478bd9Sstevel@tonic-gate (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_drain_reqs, 1483*7c478bd9Sstevel@tonic-gate ph_impl, (usb_opaque_t)((uintptr_t)time), usb_flags, cb, cb_arg); 1484*7c478bd9Sstevel@tonic-gate 1485*7c478bd9Sstevel@tonic-gate return (USB_SUCCESS); 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate /* 1490*7c478bd9Sstevel@tonic-gate * usba_pipe_sync_drain_reqs 1491*7c478bd9Sstevel@tonic-gate * this function blocks until there are no more requests 1492*7c478bd9Sstevel@tonic-gate * owned by this dip on the pipe 1493*7c478bd9Sstevel@tonic-gate * 1494*7c478bd9Sstevel@tonic-gate * Arguments: 1495*7c478bd9Sstevel@tonic-gate * dip - devinfo pointer 1496*7c478bd9Sstevel@tonic-gate * ph_impl - pipe impl handle 1497*7c478bd9Sstevel@tonic-gate * timeout - timeout in seconds 1498*7c478bd9Sstevel@tonic-gate * Returns: 1499*7c478bd9Sstevel@tonic-gate * USB_SUCCESS - pipe successfully reset or request queued 1500*7c478bd9Sstevel@tonic-gate * USB_FAILURE - timeout 1501*7c478bd9Sstevel@tonic-gate * USB_* - see usbai.h 1502*7c478bd9Sstevel@tonic-gate */ 1503*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1504*7c478bd9Sstevel@tonic-gate int 1505*7c478bd9Sstevel@tonic-gate usba_pipe_sync_drain_reqs(dev_info_t *dip, 1506*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl, 1507*7c478bd9Sstevel@tonic-gate usba_pipe_async_req_t *request, 1508*7c478bd9Sstevel@tonic-gate usb_flags_t usb_flags) 1509*7c478bd9Sstevel@tonic-gate { 1510*7c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t) 1511*7c478bd9Sstevel@tonic-gate ph_impl); 1512*7c478bd9Sstevel@tonic-gate int i; 1513*7c478bd9Sstevel@tonic-gate int timeout = 100 * (int)((uintptr_t)(request->arg)); 1514*7c478bd9Sstevel@tonic-gate /* delay will be 10 ms */ 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1519*7c478bd9Sstevel@tonic-gate "usba_pipe_sync_drain_reqs: " 1520*7c478bd9Sstevel@tonic-gate "dip=0x%p ph_data=0x%p timeout=%d ref=%d req=%d", 1521*7c478bd9Sstevel@tonic-gate dip, ph_data, timeout, usba_get_ph_ref_count(ph_data), 1522*7c478bd9Sstevel@tonic-gate ph_data->p_req_count); 1523*7c478bd9Sstevel@tonic-gate 1524*7c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0); 1525*7c478bd9Sstevel@tonic-gate 1526*7c478bd9Sstevel@tonic-gate /* 1527*7c478bd9Sstevel@tonic-gate * for default pipe, we need to check the active request 1528*7c478bd9Sstevel@tonic-gate * and the queue 1529*7c478bd9Sstevel@tonic-gate * Note that a pipe reset on the default pipe doesn't flush 1530*7c478bd9Sstevel@tonic-gate * the queue 1531*7c478bd9Sstevel@tonic-gate * for all other pipes we just check ref and req count since 1532*7c478bd9Sstevel@tonic-gate * these pipes are unshared 1533*7c478bd9Sstevel@tonic-gate */ 1534*7c478bd9Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) { 1535*7c478bd9Sstevel@tonic-gate for (i = 0; (i < timeout) || (request->arg == 0); i++) { 1536*7c478bd9Sstevel@tonic-gate usba_list_entry_t *next, *tmpnext; 1537*7c478bd9Sstevel@tonic-gate usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *) 1538*7c478bd9Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp; 1539*7c478bd9Sstevel@tonic-gate int found = 0; 1540*7c478bd9Sstevel@tonic-gate int count = 0; 1541*7c478bd9Sstevel@tonic-gate 1542*7c478bd9Sstevel@tonic-gate /* active_req_wrp is only for control pipes */ 1543*7c478bd9Sstevel@tonic-gate if ((req_wrp == NULL) || (req_wrp->wr_dip != dip)) { 1544*7c478bd9Sstevel@tonic-gate /* walk the queue */ 1545*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_queue.list_mutex); 1546*7c478bd9Sstevel@tonic-gate next = ph_data->p_queue.next; 1547*7c478bd9Sstevel@tonic-gate while (next != NULL) { 1548*7c478bd9Sstevel@tonic-gate mutex_enter(&next->list_mutex); 1549*7c478bd9Sstevel@tonic-gate req_wrp = (usba_req_wrapper_t *) 1550*7c478bd9Sstevel@tonic-gate next->private; 1551*7c478bd9Sstevel@tonic-gate found = (req_wrp->wr_dip == dip); 1552*7c478bd9Sstevel@tonic-gate if (found) { 1553*7c478bd9Sstevel@tonic-gate mutex_exit(&next->list_mutex); 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate break; 1556*7c478bd9Sstevel@tonic-gate } 1557*7c478bd9Sstevel@tonic-gate tmpnext = next->next; 1558*7c478bd9Sstevel@tonic-gate mutex_exit(&next->list_mutex); 1559*7c478bd9Sstevel@tonic-gate next = tmpnext; 1560*7c478bd9Sstevel@tonic-gate count++; 1561*7c478bd9Sstevel@tonic-gate } 1562*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_queue.list_mutex); 1563*7c478bd9Sstevel@tonic-gate if (found == 0) { 1564*7c478bd9Sstevel@tonic-gate break; 1565*7c478bd9Sstevel@tonic-gate } 1566*7c478bd9Sstevel@tonic-gate } 1567*7c478bd9Sstevel@tonic-gate 1568*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1569*7c478bd9Sstevel@tonic-gate "usb_pipe_sync_drain_reqs: " 1570*7c478bd9Sstevel@tonic-gate "cnt=%d active_req_wrp=0x%p", 1571*7c478bd9Sstevel@tonic-gate count, ph_data->p_active_cntrl_req_wrp); 1572*7c478bd9Sstevel@tonic-gate 1573*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1574*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(10000)); 1575*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1576*7c478bd9Sstevel@tonic-gate } 1577*7c478bd9Sstevel@tonic-gate } else { 1578*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex); 1579*7c478bd9Sstevel@tonic-gate for (i = 0; (i < timeout) || (request->arg == 0); i++) { 1580*7c478bd9Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0); 1581*7c478bd9Sstevel@tonic-gate if (ph_data->p_req_count || 1582*7c478bd9Sstevel@tonic-gate (ph_data->p_ph_impl->usba_ph_ref_count > 1)) { 1583*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex); 1584*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1585*7c478bd9Sstevel@tonic-gate delay(drv_usectohz(10000)); 1586*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex); 1587*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex); 1588*7c478bd9Sstevel@tonic-gate } else { 1589*7c478bd9Sstevel@tonic-gate break; 1590*7c478bd9Sstevel@tonic-gate } 1591*7c478bd9Sstevel@tonic-gate } 1592*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex); 1593*7c478bd9Sstevel@tonic-gate } 1594*7c478bd9Sstevel@tonic-gate 1595*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1596*7c478bd9Sstevel@tonic-gate "usb_pipe_sync_drain_reqs: timeout=%d active_req_wrp=0x%p req=%d", 1597*7c478bd9Sstevel@tonic-gate i, ph_data->p_active_cntrl_req_wrp, ph_data->p_req_count); 1598*7c478bd9Sstevel@tonic-gate 1599*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex); 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate usba_release_ph_data(ph_impl); 1602*7c478bd9Sstevel@tonic-gate 1603*7c478bd9Sstevel@tonic-gate return (i >= timeout ? USB_FAILURE : USB_SUCCESS); 1604*7c478bd9Sstevel@tonic-gate } 1605*7c478bd9Sstevel@tonic-gate 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate /* 1608*7c478bd9Sstevel@tonic-gate * usba_persistent_pipe_open 1609*7c478bd9Sstevel@tonic-gate * Open all the pipes marked persistent for this device 1610*7c478bd9Sstevel@tonic-gate */ 1611*7c478bd9Sstevel@tonic-gate int 1612*7c478bd9Sstevel@tonic-gate usba_persistent_pipe_open(usba_device_t *usba_device) 1613*7c478bd9Sstevel@tonic-gate { 1614*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl; 1615*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle; 1616*7c478bd9Sstevel@tonic-gate int i; 1617*7c478bd9Sstevel@tonic-gate int rval = USB_SUCCESS; 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1620*7c478bd9Sstevel@tonic-gate "usba_persistent_pipe_open: usba_device=0x%p", usba_device); 1621*7c478bd9Sstevel@tonic-gate 1622*7c478bd9Sstevel@tonic-gate if (usba_device != NULL) { 1623*7c478bd9Sstevel@tonic-gate /* default pipe is the first one to be opened */ 1624*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 1625*7c478bd9Sstevel@tonic-gate for (i = 0; (rval == USB_SUCCESS) && 1626*7c478bd9Sstevel@tonic-gate (i < USBA_N_ENDPOINTS); i++) { 1627*7c478bd9Sstevel@tonic-gate 1628*7c478bd9Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[i]; 1629*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 1630*7c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_flags & USBA_PH_DATA_PERSISTENT) { 1631*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_flags &= 1632*7c478bd9Sstevel@tonic-gate ~USBA_PH_DATA_PERSISTENT; 1633*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1634*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 1635*7c478bd9Sstevel@tonic-gate 1636*7c478bd9Sstevel@tonic-gate rval = usb_pipe_open(ph_impl->usba_ph_dip, 1637*7c478bd9Sstevel@tonic-gate &ph_impl->usba_ph_ep, 1638*7c478bd9Sstevel@tonic-gate &ph_impl->usba_ph_policy, 1639*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, 1640*7c478bd9Sstevel@tonic-gate &pipe_handle); 1641*7c478bd9Sstevel@tonic-gate 1642*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(DPRINT_MASK_USBAI, 1643*7c478bd9Sstevel@tonic-gate usbai_log_handle, 1644*7c478bd9Sstevel@tonic-gate "usba_persistent_pipe_open: " 1645*7c478bd9Sstevel@tonic-gate "ep_index=%d, rval=%d", i, rval); 1646*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 1647*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1650*7c478bd9Sstevel@tonic-gate } 1651*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 1652*7c478bd9Sstevel@tonic-gate } 1653*7c478bd9Sstevel@tonic-gate 1654*7c478bd9Sstevel@tonic-gate return (rval); 1655*7c478bd9Sstevel@tonic-gate } 1656*7c478bd9Sstevel@tonic-gate 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate /* 1659*7c478bd9Sstevel@tonic-gate * usba_persistent_pipe_close 1660*7c478bd9Sstevel@tonic-gate * Close all pipes of this device and mark them persistent 1661*7c478bd9Sstevel@tonic-gate */ 1662*7c478bd9Sstevel@tonic-gate void 1663*7c478bd9Sstevel@tonic-gate usba_persistent_pipe_close(usba_device_t *usba_device) 1664*7c478bd9Sstevel@tonic-gate { 1665*7c478bd9Sstevel@tonic-gate usba_ph_impl_t *ph_impl; 1666*7c478bd9Sstevel@tonic-gate usb_pipe_handle_t pipe_handle; 1667*7c478bd9Sstevel@tonic-gate int i; 1668*7c478bd9Sstevel@tonic-gate 1669*7c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle, 1670*7c478bd9Sstevel@tonic-gate "usba_persistent_pipe_close: usba_device=0x%p", usba_device); 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate if (usba_device != NULL) { 1673*7c478bd9Sstevel@tonic-gate /* default pipe is the last one to be closed */ 1674*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate for (i = (USBA_N_ENDPOINTS - 1); i >= 0; i--) { 1677*7c478bd9Sstevel@tonic-gate ph_impl = &usba_device->usb_ph_list[i]; 1678*7c478bd9Sstevel@tonic-gate if (ph_impl->usba_ph_data != NULL) { 1679*7c478bd9Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex); 1680*7c478bd9Sstevel@tonic-gate ph_impl->usba_ph_flags |= 1681*7c478bd9Sstevel@tonic-gate USBA_PH_DATA_PERSISTENT; 1682*7c478bd9Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex); 1683*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 1684*7c478bd9Sstevel@tonic-gate 1685*7c478bd9Sstevel@tonic-gate pipe_handle = (usb_pipe_handle_t)ph_impl; 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate usb_pipe_close(ph_impl->usba_ph_dip, 1688*7c478bd9Sstevel@tonic-gate pipe_handle, 1689*7c478bd9Sstevel@tonic-gate USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, 1690*7c478bd9Sstevel@tonic-gate NULL, NULL); 1691*7c478bd9Sstevel@tonic-gate mutex_enter(&usba_device->usb_mutex); 1692*7c478bd9Sstevel@tonic-gate ASSERT(ph_impl->usba_ph_data == NULL); 1693*7c478bd9Sstevel@tonic-gate } 1694*7c478bd9Sstevel@tonic-gate } 1695*7c478bd9Sstevel@tonic-gate mutex_exit(&usba_device->usb_mutex); 1696*7c478bd9Sstevel@tonic-gate } 1697*7c478bd9Sstevel@tonic-gate } 1698