Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / usb / usba / usbai_pipe_mgmt.c
blob047f2d88b4fd12526cdce58720f6de2ad379bd98
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
26 * Copyright 2016 Joyent, Inc.
31 * USBA: Solaris USB Architecture support
33 * all functions exposed to client drivers have prefix usb_ while all USBA
34 * internal functions or functions exposed to HCD or hubd only have prefix
35 * usba_
37 * this file contains all USBAI pipe management
38 * usb_pipe_open()
39 * usb_pipe_close()
40 * usb_pipe_set_private()
41 * usb_pipe_get_private()
42 * usb_pipe_abort()
43 * usb_pipe_reset()
44 * usb_pipe_drain_reqs()
46 #define USBA_FRAMEWORK
47 #include <sys/usb/usba/usba_impl.h>
48 #include <sys/usb/usba/hcdi_impl.h>
49 #include <sys/atomic.h>
51 extern pri_t maxclsyspri;
52 extern pri_t minclsyspri;
54 /* function prototypes */
55 static void usba_pipe_do_async_func_thread(void *arg);
56 static int usba_pipe_sync_close(dev_info_t *, usba_ph_impl_t *,
57 usba_pipe_async_req_t *, usb_flags_t);
58 static int usba_pipe_sync_reset(dev_info_t *, usba_ph_impl_t *,
59 usba_pipe_async_req_t *, usb_flags_t);
60 static int usba_pipe_sync_drain_reqs(dev_info_t *, usba_ph_impl_t *,
61 usba_pipe_async_req_t *, usb_flags_t);
63 /* local tunables */
64 int usba_drain_timeout = 1000; /* in ms */
66 /* return the default pipe for this device */
67 usb_pipe_handle_t
68 usba_get_dflt_pipe_handle(dev_info_t *dip)
70 usba_device_t *usba_device;
71 usb_pipe_handle_t pipe_handle = NULL;
73 if (dip) {
74 usba_device = usba_get_usba_device(dip);
75 if (usba_device) {
76 pipe_handle =
77 (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
81 return (pipe_handle);
85 /* return dip owner of pipe_handle */
86 dev_info_t *
87 usba_get_dip(usb_pipe_handle_t pipe_handle)
89 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
90 dev_info_t *dip = NULL;
92 if (ph_impl) {
93 mutex_enter(&ph_impl->usba_ph_mutex);
94 dip = ph_impl->usba_ph_dip;
95 mutex_exit(&ph_impl->usba_ph_mutex);
98 return (dip);
102 usb_pipe_handle_t
103 usba_usbdev_to_dflt_pipe_handle(usba_device_t *usba_device)
105 usb_pipe_handle_t pipe_handle = NULL;
107 if ((usba_device) &&
108 (usba_device->usb_ph_list[0].usba_ph_data != NULL)) {
109 pipe_handle = (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
112 return (pipe_handle);
116 usba_pipe_handle_data_t *
117 usba_get_ph_data(usb_pipe_handle_t pipe_handle)
119 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
120 usba_pipe_handle_data_t *ph_data = NULL;
122 if (ph_impl) {
123 mutex_enter(&ph_impl->usba_ph_mutex);
124 ASSERT(ph_impl->usba_ph_ref_count >= 0);
125 ph_data = ph_impl->usba_ph_data;
126 mutex_exit(&ph_impl->usba_ph_mutex);
129 return (ph_data);
133 usb_pipe_handle_t
134 usba_get_pipe_handle(usba_pipe_handle_data_t *ph_data)
136 usb_pipe_handle_t ph = NULL;
138 if (ph_data) {
139 mutex_enter(&ph_data->p_mutex);
140 ASSERT(ph_data->p_req_count >= 0);
141 ph = (usb_pipe_handle_t)ph_data->p_ph_impl;
142 mutex_exit(&ph_data->p_mutex);
145 return (ph);
150 * opaque to pipe handle impl translation with incr of ref count. The caller
151 * must release ph_data when done. Increment the ref count ensures that
152 * the ph_data will not be freed underneath us.
154 usba_pipe_handle_data_t *
155 usba_hold_ph_data(usb_pipe_handle_t pipe_handle)
157 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
158 usba_pipe_handle_data_t *ph_data = NULL;
160 if (ph_impl) {
161 mutex_enter(&ph_impl->usba_ph_mutex);
163 switch (ph_impl->usba_ph_state) {
164 case USB_PIPE_STATE_IDLE:
165 case USB_PIPE_STATE_ACTIVE:
166 case USB_PIPE_STATE_ERROR:
167 ph_data = ph_impl->usba_ph_data;
168 ph_impl->usba_ph_ref_count++;
169 break;
170 case USB_PIPE_STATE_CLOSED:
171 case USB_PIPE_STATE_CLOSING:
172 default:
173 break;
176 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
177 "usba_hold_ph_data: ph_impl=0x%p state=%d ref=%d",
178 (void *)ph_impl, ph_impl->usba_ph_state,
179 ph_impl->usba_ph_ref_count);
181 mutex_exit(&ph_impl->usba_ph_mutex);
184 return (ph_data);
188 void
189 usba_release_ph_data(usba_ph_impl_t *ph_impl)
191 if (ph_impl) {
192 mutex_enter(&ph_impl->usba_ph_mutex);
194 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
195 "usba_release_ph_data: "
196 "ph_impl=0x%p state=%d ref=%d",
197 (void *)ph_impl, ph_impl->usba_ph_state,
198 ph_impl->usba_ph_ref_count);
200 if (ph_impl->usba_ph_data) {
201 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
202 "usba_release_ph_data: req_count=%d",
203 ph_impl->usba_ph_data->p_req_count);
204 ASSERT(ph_impl->usba_ph_data->p_req_count >= 0);
206 ph_impl->usba_ph_ref_count--;
207 ASSERT(ph_impl->usba_ph_ref_count >= 0);
209 mutex_exit(&ph_impl->usba_ph_mutex);
215 * get pipe state from ph_data
217 usb_pipe_state_t
218 usba_get_ph_state(usba_pipe_handle_data_t *ph_data)
220 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
221 usb_pipe_state_t pipe_state;
223 ASSERT(mutex_owned(&ph_data->p_mutex));
224 mutex_enter(&ph_impl->usba_ph_mutex);
225 pipe_state = ph_impl->usba_ph_state;
226 mutex_exit(&ph_impl->usba_ph_mutex);
228 return (pipe_state);
233 * get ref_count from ph_data
236 usba_get_ph_ref_count(usba_pipe_handle_data_t *ph_data)
238 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
239 int ref_count;
241 mutex_enter(&ph_impl->usba_ph_mutex);
242 ref_count = ph_impl->usba_ph_ref_count;
243 mutex_exit(&ph_impl->usba_ph_mutex);
245 return (ref_count);
250 * new pipe state
251 * We need to hold both pipe mutex and ph_impl mutex
253 void
254 usba_pipe_new_state(usba_pipe_handle_data_t *ph_data, usb_pipe_state_t state)
256 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
258 ASSERT(mutex_owned(&ph_data->p_mutex));
260 mutex_enter(&ph_impl->usba_ph_mutex);
261 ASSERT(ph_data->p_req_count >= 0);
262 ASSERT(ph_impl->usba_ph_ref_count >= 0);
264 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
265 "usba_pipe_new_state: "
266 "ph_data=0x%p old=%s new=%s ref=%d req=%d",
267 (void *)ph_data, usb_str_pipe_state(ph_impl->usba_ph_state),
268 usb_str_pipe_state(state),
269 ph_impl->usba_ph_ref_count, ph_data->p_req_count);
271 switch (ph_impl->usba_ph_state) {
272 case USB_PIPE_STATE_IDLE:
273 case USB_PIPE_STATE_ACTIVE:
274 case USB_PIPE_STATE_ERROR:
275 case USB_PIPE_STATE_CLOSED:
276 ph_impl->usba_ph_state = state;
277 break;
278 case USB_PIPE_STATE_CLOSING:
279 default:
280 break;
282 mutex_exit(&ph_impl->usba_ph_mutex);
287 * async function execution support
288 * Arguments:
289 * dip - devinfo pointer
290 * sync_func - function to be executed
291 * ph_impl - impl pipehandle
292 * arg - opaque arg
293 * usb_flags - none
294 * callback - function to be called on completion, may be NULL
295 * callback_arg - argument for callback function
297 * Note: The caller must do a hold on ph_data
298 * We sleep for memory resources and taskq_dispatch which will ensure
299 * that this function succeeds
302 usba_pipe_setup_func_call(
303 dev_info_t *dip,
304 int (*sync_func)(dev_info_t *,
305 usba_ph_impl_t *, usba_pipe_async_req_t *,
306 usb_flags_t),
307 usba_ph_impl_t *ph_impl,
308 usb_opaque_t arg,
309 usb_flags_t usb_flags,
310 void (*callback)(usb_pipe_handle_t,
311 usb_opaque_t, int, usb_cb_flags_t),
312 usb_opaque_t callback_arg)
314 usba_pipe_async_req_t *request;
315 usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl;
316 usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
317 int rval = USB_SUCCESS;
318 usb_cb_flags_t callback_flags;
320 USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
321 "usba_pipe_setup_func_call: ph_impl=0x%p, func=0x%p",
322 (void *)ph_impl, (void *)sync_func);
324 if (((usb_flags & USB_FLAGS_SLEEP) == 0) && (callback == NULL)) {
325 usba_release_ph_data(ph_impl);
326 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
327 "usba_pipe_setup_func_call: async request with "
328 "no callback");
330 return (USB_INVALID_ARGS);
333 request = kmem_zalloc(sizeof (usba_pipe_async_req_t), KM_SLEEP);
334 request->dip = dip;
335 request->ph_impl = ph_impl;
336 request->arg = arg;
339 * OR in sleep flag. regardless of calling sync_func directly
340 * or in a new thread, we will always wait for completion
342 request->usb_flags = usb_flags | USB_FLAGS_SLEEP;
343 request->sync_func = sync_func;
344 request->callback = callback;
345 request->callback_arg = callback_arg;
347 if (usb_flags & USB_FLAGS_SLEEP) {
348 rval = sync_func(dip, ph_impl, request, usb_flags);
349 kmem_free(request, sizeof (usba_pipe_async_req_t));
351 } else if (usba_async_ph_req(ph_data,
352 usba_pipe_do_async_func_thread,
353 (void *)request, USB_FLAGS_SLEEP) != USB_SUCCESS) {
354 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
355 "usb_async_req failed: ph_impl=0x%p, func=0x%p",
356 (void *)ph_impl, (void *)sync_func);
358 if (callback) {
359 callback_flags =
360 usba_check_intr_context(USB_CB_ASYNC_REQ_FAILED);
361 callback(pipe_handle, callback_arg, USB_FAILURE,
362 callback_flags);
365 kmem_free(request, sizeof (usba_pipe_async_req_t));
366 usba_release_ph_data(ph_impl);
369 return (rval);
374 * taskq thread function to execute function synchronously
375 * Note: caller must have done a hold on ph_data
377 static void
378 usba_pipe_do_async_func_thread(void *arg)
380 usba_pipe_async_req_t *request = (usba_pipe_async_req_t *)arg;
381 usba_ph_impl_t *ph_impl = request->ph_impl;
382 usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl;
383 int rval;
384 usb_cb_flags_t cb_flags = USB_CB_NO_INFO;
386 if ((rval = request->sync_func(request->dip, ph_impl,
387 request, request->usb_flags | USB_FLAGS_SLEEP)) !=
388 USB_SUCCESS) {
389 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
390 "sync func failed (%d)", rval);
393 if (request->callback) {
394 request->callback(pipe_handle, request->callback_arg, rval,
395 cb_flags);
398 kmem_free(request, sizeof (usba_pipe_async_req_t));
403 * default endpoint descriptor and pipe policy
405 usb_ep_descr_t usba_default_ep_descr =
406 {7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0};
408 /* set some meaningful defaults */
409 static usb_pipe_policy_t usba_default_ep_pipe_policy = {3};
413 * usb_get_ep_index: create an index from endpoint address that can
414 * be used to index into endpoint pipe lists
416 uchar_t
417 usb_get_ep_index(uint8_t ep_addr)
419 return ((ep_addr & USB_EP_NUM_MASK) +
420 ((ep_addr & USB_EP_DIR_MASK) ? 16 : 0));
425 * pipe management
426 * utility functions to init and destroy a pipehandle
428 static int
429 usba_init_pipe_handle(dev_info_t *dip,
430 usba_device_t *usba_device,
431 usb_ep_descr_t *ep,
432 usb_ep_xdescr_t *ep_xdescr,
433 usb_pipe_policy_t *pipe_policy,
434 usba_ph_impl_t *ph_impl)
436 usb_ep_xdescr_t xep;
437 int instance = ddi_get_instance(dip);
438 unsigned int def_instance = instance;
439 static unsigned int anon_instance = 0;
440 char tq_name[TASKQ_NAMELEN];
442 usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
443 ddi_iblock_cookie_t iblock_cookie =
444 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
445 hcdi_iblock_cookie;
447 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
448 "usba_init_pipe_handle: "
449 "usba_device=0x%p ep=0x%x", (void *)usba_device,
450 ep->bEndpointAddress);
451 mutex_init(&ph_data->p_mutex, NULL, MUTEX_DRIVER, iblock_cookie);
453 /* just to keep warlock happy, there is no contention yet */
454 mutex_enter(&ph_data->p_mutex);
455 mutex_enter(&usba_device->usb_mutex);
457 ASSERT(pipe_policy->pp_max_async_reqs);
459 if (instance != -1) {
460 (void) snprintf(tq_name, sizeof (tq_name),
461 "USB_%s_%x_pipehndl_tq_%d",
462 ddi_driver_name(dip), ep->bEndpointAddress, instance);
463 } else {
464 def_instance = atomic_inc_32_nv(&anon_instance);
466 (void) snprintf(tq_name, sizeof (tq_name),
467 "USB_%s_%x_pipehndl_tq_%d_",
468 ddi_driver_name(dip), ep->bEndpointAddress, def_instance);
471 ph_data->p_taskq = taskq_create(tq_name,
472 pipe_policy->pp_max_async_reqs + 1,
473 ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
474 USB_EP_ATTR_ISOCH) ?
475 (maxclsyspri - 5) : minclsyspri,
476 2 * (pipe_policy->pp_max_async_reqs + 1),
477 8 * (pipe_policy->pp_max_async_reqs + 1),
478 TASKQ_PREPOPULATE);
481 * Create a shared taskq.
483 if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
484 int iface = usb_get_if_number(dip);
485 if (iface < 0) {
486 /* we own the device, use first entry */
487 iface = 0;
490 if (instance != -1) {
491 (void) snprintf(tq_name, sizeof (tq_name),
492 "USB_%s_%x_shared_tq_%d",
493 ddi_driver_name(dip), ep->bEndpointAddress,
494 instance);
495 } else {
496 (void) snprintf(tq_name, sizeof (tq_name),
497 "USB_%s_%x_shared_tq_%d_",
498 ddi_driver_name(dip), ep->bEndpointAddress,
499 def_instance);
502 if (usba_device->usb_shared_taskq_ref_count[iface] == 0) {
503 usba_device->usb_shared_taskq[iface] =
504 taskq_create(tq_name,
505 1, /* Number threads. */
506 maxclsyspri - 5, /* Priority */
507 1, /* minalloc */
508 USBA_N_ENDPOINTS + 4, /* maxalloc */
509 TASKQ_PREPOPULATE);
510 ASSERT(usba_device->usb_shared_taskq[iface] != NULL);
512 usba_device->usb_shared_taskq_ref_count[iface]++;
516 * In the future, when we may have different versions of the extended
517 * endpoint descriptor, they should be normalized to the current version
518 * here such that all of the HCI drivers have a consistent view of the
519 * world. The extended descriptor may be NULL if we are opening the
520 * default control endpoint; however, we create a uniform view for the
521 * HCI drivers.
523 if (ep_xdescr == NULL) {
524 bzero(&xep, sizeof (usb_ep_xdescr_t));
525 xep.uex_version = USB_EP_XDESCR_CURRENT_VERSION;
526 xep.uex_ep = *ep;
527 ep_xdescr = &xep;
530 ph_data->p_dip = dip;
531 ph_data->p_usba_device = usba_device;
532 ph_data->p_ep = *ep;
533 ph_data->p_xep = *ep_xdescr;
534 ph_data->p_ph_impl = ph_impl;
535 if ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
536 USB_EP_ATTR_ISOCH) {
537 ph_data->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
540 /* fix up the MaxPacketSize if it is the default endpoint descr */
541 if ((ep == &usba_default_ep_descr) && usba_device) {
542 uint16_t maxpktsize;
544 maxpktsize = usba_device->usb_dev_descr->bMaxPacketSize0;
545 USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
546 "adjusting max packet size from %d to %d",
547 ph_data->p_ep.wMaxPacketSize, maxpktsize);
549 ph_data->p_ep.wMaxPacketSize = maxpktsize;
552 /* now update usba_ph_impl structure */
553 mutex_enter(&ph_impl->usba_ph_mutex);
554 ph_impl->usba_ph_dip = dip;
555 ph_impl->usba_ph_ep = ph_data->p_ep;
556 ph_impl->usba_ph_policy = ph_data->p_policy = *pipe_policy;
557 mutex_exit(&ph_impl->usba_ph_mutex);
559 usba_init_list(&ph_data->p_queue, (usb_opaque_t)ph_data, iblock_cookie);
560 usba_init_list(&ph_data->p_cb_queue, (usb_opaque_t)ph_data,
561 iblock_cookie);
562 mutex_exit(&usba_device->usb_mutex);
563 mutex_exit(&ph_data->p_mutex);
565 return (USB_SUCCESS);
569 static void
570 usba_taskq_destroy(void *arg)
572 taskq_destroy((taskq_t *)arg);
576 static void
577 usba_destroy_pipe_handle(usba_pipe_handle_data_t *ph_data)
579 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
580 int timeout;
581 usba_device_t *usba_device;
583 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
584 "usba_destroy_pipe_handle: ph_data=0x%p", (void *)ph_data);
586 mutex_enter(&ph_data->p_mutex);
587 mutex_enter(&ph_impl->usba_ph_mutex);
589 /* check for all activity to drain */
590 for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
591 if ((ph_impl->usba_ph_ref_count <= 1) &&
592 (ph_data->p_req_count == 0)) {
594 break;
596 mutex_exit(&ph_data->p_mutex);
597 mutex_exit(&ph_impl->usba_ph_mutex);
598 ddi_msleep(1);
599 mutex_enter(&ph_data->p_mutex);
600 mutex_enter(&ph_impl->usba_ph_mutex);
604 * set state to closed here so any other thread
605 * that is waiting for the CLOSED state will
606 * continue. Otherwise, taskq_destroy might deadlock
608 ph_impl->usba_ph_data = NULL;
609 ph_impl->usba_ph_ref_count = 0;
610 ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSED;
612 if (ph_data->p_taskq) {
613 mutex_exit(&ph_data->p_mutex);
614 mutex_exit(&ph_impl->usba_ph_mutex);
615 if (taskq_member(ph_data->p_taskq, curthread)) {
617 * use system taskq to destroy ph's taskq to avoid
618 * deadlock
620 (void) taskq_dispatch(system_taskq,
621 usba_taskq_destroy, ph_data->p_taskq, TQ_SLEEP);
622 } else {
623 taskq_destroy(ph_data->p_taskq);
625 } else {
626 mutex_exit(&ph_data->p_mutex);
627 mutex_exit(&ph_impl->usba_ph_mutex);
630 usba_device = ph_data->p_usba_device;
631 mutex_enter(&ph_data->p_mutex);
632 if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
633 int iface = usb_get_if_number(ph_data->p_dip);
634 if (iface < 0) {
635 /* we own the device, use the first entry */
636 iface = 0;
638 mutex_enter(&usba_device->usb_mutex);
639 if (--usba_device->usb_shared_taskq_ref_count[iface] == 0) {
640 ph_data->p_spec_flag &= ~USBA_PH_FLAG_TQ_SHARE;
641 if (taskq_member(usba_device->usb_shared_taskq[iface],
642 curthread)) {
643 (void) taskq_dispatch(
644 system_taskq,
645 usba_taskq_destroy,
646 usba_device->usb_shared_taskq[iface],
647 TQ_SLEEP);
648 } else {
649 taskq_destroy(
650 usba_device->usb_shared_taskq[iface]);
653 mutex_exit(&usba_device->usb_mutex);
655 mutex_exit(&ph_data->p_mutex);
658 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
659 "usba_destroy_pipe_handle: destroying ph_data=0x%p",
660 (void *)ph_data);
662 usba_destroy_list(&ph_data->p_queue);
663 usba_destroy_list(&ph_data->p_cb_queue);
665 /* destroy mutexes */
666 mutex_destroy(&ph_data->p_mutex);
668 kmem_free(ph_data, sizeof (usba_pipe_handle_data_t));
673 * usba_drain_cbs:
674 * Drain the request callbacks on the pipe handle
677 usba_drain_cbs(usba_pipe_handle_data_t *ph_data, usb_cb_flags_t cb_flags,
678 usb_cr_t cr)
680 usba_req_wrapper_t *req_wrp;
681 int flush_requests = 1;
682 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
683 int timeout;
684 int rval = USB_SUCCESS;
686 ASSERT(mutex_owned(&ph_data->p_mutex));
688 mutex_enter(&ph_impl->usba_ph_mutex);
689 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
690 "usba_drain_cbs: ph_data=0x%p ref=%d req=%d cb=0x%x cr=%d",
691 (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count,
692 cb_flags, cr);
693 ASSERT(ph_data->p_req_count >= 0);
694 mutex_exit(&ph_impl->usba_ph_mutex);
696 if (ph_data->p_dip) {
697 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
698 USB_DPRINTF_L4(DPRINT_MASK_USBAI,
699 usbai_log_handle,
700 "no flushing on default pipe!");
702 flush_requests = 0;
706 if (flush_requests) {
707 /* flush all requests in the pipehandle queue */
708 while ((req_wrp = (usba_req_wrapper_t *)
709 usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
710 mutex_exit(&ph_data->p_mutex);
711 usba_do_req_exc_cb(req_wrp, cr, cb_flags);
712 mutex_enter(&ph_data->p_mutex);
717 * wait for any callbacks in progress but don't wait for
718 * for queued requests on the default pipe
720 for (timeout = 0; (timeout < usba_drain_timeout) &&
721 (ph_data->p_req_count >
722 usba_list_entry_count(&ph_data->p_queue));
723 timeout++) {
724 mutex_exit(&ph_data->p_mutex);
725 ddi_msleep(1);
726 mutex_enter(&ph_data->p_mutex);
729 mutex_enter(&ph_impl->usba_ph_mutex);
730 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
731 "usba_drain_cbs done: ph_data=0x%p ref=%d req=%d",
732 (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count);
733 mutex_exit(&ph_impl->usba_ph_mutex);
735 if (timeout == usba_drain_timeout) {
736 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
737 "draining callbacks timed out!");
739 rval = USB_FAILURE;
742 return (rval);
747 * usb_pipe_open():
749 * Before using any pipe including the default pipe, it should be opened
750 * using usb_pipe_open(). On a successful open, a pipe handle is returned
751 * for use in other usb_pipe_*() functions
753 * The default pipe can only be opened by the hub driver
755 * The bandwidth has been allocated and guaranteed on successful
756 * opening of an isoc/intr pipes.
758 * Only the default pipe can be shared. all other control pipes
759 * are excusively opened by default.
760 * A pipe policy and endpoint descriptor must always be provided
761 * except for default pipe
763 * Arguments:
764 * dip - devinfo ptr
765 * ep - endpoint descriptor pointer
766 * pipe_policy - pointer to pipe policy which provides hints on how
767 * the pipe will be used.
768 * flags - USB_FLAGS_SLEEP wait for resources
769 * to become available
770 * pipe_handle - a pipe handle pointer. On a successful open,
771 * a pipe_handle is returned in this pointer.
773 * Return values:
774 * USB_SUCCESS - open succeeded
775 * USB_FAILURE - unspecified open failure or pipe is already open
776 * USB_NO_RESOURCES - no resources were available to complete the open
777 * USB_NO_BANDWIDTH - no bandwidth available (isoc/intr pipes)
778 * USB_* - refer to usbai.h
781 usb_pipe_xopen(
782 dev_info_t *dip,
783 usb_ep_xdescr_t *ep_xdesc,
784 usb_pipe_policy_t *pipe_policy,
785 usb_flags_t usb_flags,
786 usb_pipe_handle_t *pipe_handle)
788 usb_ep_descr_t *ep;
789 usba_device_t *usba_device;
790 int rval;
791 usba_pipe_handle_data_t *ph_data;
792 usba_ph_impl_t *ph_impl;
793 uchar_t ep_index;
794 int kmflag;
795 size_t size;
797 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
798 "usb_pipe_open:\n\t"
799 "dip=0x%p ep_xdesc=0x%p pp=0x%p uf=0x%x ph=0x%p",
800 (void *)dip, (void *)ep_xdesc, (void *)pipe_policy, usb_flags,
801 (void *)pipe_handle);
803 if ((dip == NULL) || (pipe_handle == NULL)) {
805 return (USB_INVALID_ARGS);
808 if ((ep_xdesc != NULL) &&
809 ((ep_xdesc->uex_version != USB_EP_XDESCR_CURRENT_VERSION) ||
810 ((ep_xdesc->uex_flags & ~USB_EP_XFLAGS_SS_COMP) != 0))) {
812 return (USB_INVALID_ARGS);
815 if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
817 return (USB_INVALID_CONTEXT);
819 usba_device = usba_get_usba_device(dip);
822 * Check the device's speed. If we're being asked to open anything other
823 * than the default endpoint and the device is superspeed or greater and
824 * we only have a usb_ep_descr_t and not the full endpoint data, then
825 * this was coming through usb_pipe_open() and we need to fail this
826 * call.
828 * Some drivers technically cheat and open the default control endpoint
829 * even though they're not supposed to. ugen appears to be the main
830 * offender. To deal with this, we check to see if the endpoint
831 * descriptor bcmps to our default and give them a break, since we don't
832 * need extended info for default control endpoints.
834 if (ep_xdesc != NULL && ep_xdesc->uex_flags == 0 &&
835 bcmp(&ep_xdesc->uex_ep, &usba_default_ep_descr,
836 sizeof (usb_ep_descr_t)) != 0 &&
837 usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) {
838 const char *dname = ddi_driver_name(dip);
839 const char *prod, *mfg;
841 prod = usba_device->usb_product_str;
842 if (prod == NULL)
843 prod = "Unknown Device";
844 mfg = usba_device->usb_mfg_str;
845 if (mfg == NULL)
846 mfg = "Unknown Manufacturer";
847 cmn_err(CE_NOTE, "driver %s attempting to open non-default "
848 "of a USB 3.0 or newer device through usb_pipe_open(). "
849 "%s must be updated to use usb_pipe_xopen() to work with "
850 "USB device %s %s.", dname, dname, mfg, prod);
851 return (USB_FAILURE);
854 if ((ep_xdesc != NULL) && (pipe_policy == NULL)) {
855 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
856 "usb_pipe_open: null pipe policy");
858 return (USB_INVALID_ARGS);
861 /* is the device still connected? */
862 if ((ep_xdesc != NULL) & DEVI_IS_DEVICE_REMOVED(dip)) {
863 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
864 "usb_pipe_open: device has been removed");
866 return (USB_FAILURE);
871 * if a null endpoint pointer was passed, use the default
872 * endpoint descriptor
874 if (ep_xdesc == NULL) {
875 if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
876 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
877 "usb_pipe_open: not allowed to open def pipe");
879 return (USB_INVALID_PERM);
882 ep = &usba_default_ep_descr;
883 pipe_policy = &usba_default_ep_pipe_policy;
884 } else {
885 ep = &ep_xdesc->uex_ep;
888 if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
889 if (((ep->bmAttributes & USB_EP_ATTR_MASK) ==
890 USB_EP_ATTR_CONTROL) ||
891 ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
892 USB_EP_ATTR_ISOCH)) {
893 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
894 "usb_pipe_open: shared taskq not allowed with "
895 "ctrl or isoch pipe");
897 return (USB_INVALID_ARGS);
901 kmflag = (usb_flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
902 size = sizeof (usba_pipe_handle_data_t);
904 if ((ph_data = kmem_zalloc(size, kmflag)) == NULL) {
906 return (USB_NO_RESOURCES);
909 /* check if pipe is already open and if so fail */
910 ep_index = usb_get_ep_index(ep->bEndpointAddress);
911 ph_impl = &usba_device->usb_ph_list[ep_index];
913 mutex_enter(&usba_device->usb_mutex);
914 mutex_enter(&ph_impl->usba_ph_mutex);
916 if (ph_impl->usba_ph_data) {
917 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
918 "usb_pipe_open: pipe to ep %d already open", ep_index);
919 mutex_exit(&ph_impl->usba_ph_mutex);
920 mutex_exit(&usba_device->usb_mutex);
921 kmem_free(ph_data, size);
923 return (USB_BUSY);
926 ph_impl->usba_ph_data = ph_data;
928 mutex_exit(&ph_impl->usba_ph_mutex);
929 mutex_exit(&usba_device->usb_mutex);
931 if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
932 mutex_enter(&ph_data->p_mutex);
933 ph_data->p_spec_flag |= USBA_PH_FLAG_TQ_SHARE;
934 mutex_exit(&ph_data->p_mutex);
938 * allocate and initialize the pipe handle
940 if ((rval = usba_init_pipe_handle(dip, usba_device,
941 ep, ep_xdesc, pipe_policy, ph_impl)) != USB_SUCCESS) {
942 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
943 "usb_pipe_open: pipe init failed (%d)", rval);
945 return (rval);
947 ph_data = ph_impl->usba_ph_data;
950 * ask the hcd to open the pipe
952 if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_open(ph_data,
953 usb_flags)) != USB_SUCCESS) {
954 usba_destroy_pipe_handle(ph_data);
956 *pipe_handle = NULL;
957 } else {
958 *pipe_handle = (usb_pipe_handle_t)ph_impl;
960 /* set the pipe state after a successful hcd open */
961 mutex_enter(&ph_data->p_mutex);
962 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
963 mutex_exit(&ph_data->p_mutex);
966 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
967 "usb_pipe_open: ph_impl=0x%p (0x%p)",
968 (void *)ph_impl, (void *)ph_data);
970 return (rval);
974 usb_pipe_open(
975 dev_info_t *dip,
976 usb_ep_descr_t *ep,
977 usb_pipe_policy_t *pipe_policy,
978 usb_flags_t usb_flags,
979 usb_pipe_handle_t *pipe_handle)
981 usb_ep_xdescr_t xdesc, *xp = NULL;
984 * ep may be NULL if trying to open the default control endpoint.
986 if (ep != NULL) {
987 bzero(&xdesc, sizeof (usb_ep_xdescr_t));
988 xdesc.uex_version = USB_EP_XDESCR_CURRENT_VERSION;
989 xdesc.uex_ep = *ep;
990 xp = &xdesc;
993 return (usb_pipe_xopen(dip, xp, pipe_policy, usb_flags,
994 pipe_handle));
998 * usb_pipe_close/sync_close:
1000 * Close a pipe and release all resources and free the pipe_handle.
1001 * Automatic polling, if active, will be terminated
1003 * Arguments:
1004 * dip - devinfo ptr
1005 * pipehandle - pointer to pipehandle. The pipehandle will be
1006 * zeroed on successful completion
1007 * flags - USB_FLAGS_SLEEP:
1008 * wait for resources, pipe
1009 * to become free, all callbacks completed
1010 * callback - If USB_FLAGS_SLEEP has not been specified, a
1011 * callback will be performed.
1012 * callback_arg - the first argument of the callback. Note that
1013 * the pipehandle will be zeroed and not passed
1015 * Notes:
1016 * Pipe close will always succeed regardless whether USB_FLAGS_SLEEP has been
1017 * specified or not.
1018 * An async close will always succeed if the hint in the pipe policy
1019 * has been correct about the max number of async taskq requests required.
1020 * If there are really no resources, the pipe handle will be linked into
1021 * a garbage pipe list and periodically checked by USBA until it can be
1022 * closed. This may cause a hang in the detach of the driver.
1023 * USBA will prevent the client from submitting more requests to a pipe
1024 * that is being closed
1025 * Subsequent usb_pipe_close() requests on the same pipe to USBA will
1026 * wait for the previous close(s) to finish.
1028 * Note that once we start closing a pipe, we cannot go back anymore
1029 * to a normal pipe state
1031 void
1032 usb_pipe_close(dev_info_t *dip,
1033 usb_pipe_handle_t pipe_handle,
1034 usb_flags_t usb_flags,
1035 void (*callback)(
1036 usb_pipe_handle_t pipe_handle,
1037 usb_opaque_t arg,
1038 int rval,
1039 usb_cb_flags_t flags),
1040 usb_opaque_t callback_arg)
1042 usba_pipe_handle_data_t *ph_data;
1043 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1044 usb_cb_flags_t callback_flags;
1046 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1047 "usb_pipe_close: ph=0x%p", (void *)pipe_handle);
1049 callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
1050 if ((dip == NULL) || (pipe_handle == NULL)) {
1051 if (callback) {
1052 callback(pipe_handle, callback_arg,
1053 USB_INVALID_ARGS, callback_flags);
1054 } else {
1055 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1056 usbai_log_handle,
1057 "usb_pipe_close: invalid arguments");
1060 return;
1063 if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
1065 * It is the client driver doing the pipe close,
1066 * the pipe is no longer persistent then.
1068 mutex_enter(&ph_impl->usba_ph_mutex);
1069 ph_impl->usba_ph_flags &= ~USBA_PH_DATA_PERSISTENT;
1070 mutex_exit(&ph_impl->usba_ph_mutex);
1073 if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
1074 if (callback) {
1075 callback(pipe_handle, callback_arg,
1076 USB_INVALID_CONTEXT, callback_flags);
1077 } else {
1078 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1079 usbai_log_handle,
1080 "usb_pipe_close: invalid context");
1083 return;
1086 if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
1088 /* hold pipehandle anyways since we will decrement later */
1089 mutex_enter(&ph_impl->usba_ph_mutex);
1090 ph_impl->usba_ph_ref_count++;
1091 mutex_exit(&ph_impl->usba_ph_mutex);
1093 (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
1094 ph_impl, NULL, usb_flags, callback, callback_arg);
1096 return;
1099 mutex_enter(&ph_data->p_mutex);
1101 if (USBA_IS_DEFAULT_PIPE(ph_data) &&
1102 ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0)) {
1103 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1104 "usb_pipe_close: not allowed to close def pipe");
1105 mutex_exit(&ph_data->p_mutex);
1107 usba_release_ph_data(ph_impl);
1109 if (callback) {
1110 callback(pipe_handle, callback_arg,
1111 USB_INVALID_PIPE, callback_flags);
1112 } else {
1113 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1114 usbai_log_handle,
1115 "usb_pipe_close: invalid pipe");
1118 return;
1121 mutex_exit(&ph_data->p_mutex);
1123 (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
1124 ph_impl, NULL, usb_flags, callback, callback_arg);
1128 /*ARGSUSED*/
1129 static int
1130 usba_pipe_sync_close(dev_info_t *dip, usba_ph_impl_t *ph_impl,
1131 usba_pipe_async_req_t *request, usb_flags_t usb_flags)
1133 usba_device_t *usba_device;
1134 usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
1135 (usb_pipe_handle_t)ph_impl);
1136 int attribute;
1137 uchar_t dir;
1138 int timeout;
1140 if (ph_impl == NULL) {
1142 return (USB_SUCCESS);
1145 mutex_enter(&ph_impl->usba_ph_mutex);
1146 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1147 "usba_pipe_sync_close: dip=0x%p ph_data=0x%p state=%d ref=%d",
1148 (void *)dip, (void *)ph_data, ph_impl->usba_ph_state,
1149 ph_impl->usba_ph_ref_count);
1152 * if another thread opens the pipe again, this loop could
1153 * be truly forever
1155 if ((ph_data == NULL) ||
1156 (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSING) ||
1157 (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSED)) {
1158 /* wait forever till really closed */
1159 mutex_exit(&ph_impl->usba_ph_mutex);
1160 usba_release_ph_data(ph_impl);
1162 while (usba_get_ph_data((usb_pipe_handle_t)ph_impl)) {
1163 delay(1);
1166 return (USB_SUCCESS);
1168 ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSING;
1169 mutex_exit(&ph_impl->usba_ph_mutex);
1171 mutex_enter(&ph_data->p_mutex);
1172 mutex_enter(&ph_impl->usba_ph_mutex);
1174 attribute = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
1175 dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
1177 usba_device = ph_data->p_usba_device;
1180 * For control and bulk, we will drain till ref_count <= 1 and
1181 * req_count == 0 but for isoc and intr IN, we can only wait
1182 * till the ref_count === 1 as the req_count will never go to 0
1184 for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
1185 switch (attribute) {
1186 case USB_EP_ATTR_CONTROL:
1187 case USB_EP_ATTR_BULK:
1188 if ((ph_data->p_req_count == 0) &&
1189 (ph_impl->usba_ph_ref_count <= 1)) {
1190 goto done;
1192 break;
1193 case USB_EP_ATTR_INTR:
1194 case USB_EP_ATTR_ISOCH:
1195 if (dir == USB_EP_DIR_IN) {
1196 if (ph_impl->usba_ph_ref_count <= 1) {
1197 goto done;
1199 } else if ((ph_data->p_req_count == 0) &&
1200 (ph_impl->usba_ph_ref_count <= 1)) {
1201 goto done;
1203 break;
1205 mutex_exit(&ph_impl->usba_ph_mutex);
1206 mutex_exit(&ph_data->p_mutex);
1207 ddi_msleep(1);
1208 mutex_enter(&ph_data->p_mutex);
1209 mutex_enter(&ph_impl->usba_ph_mutex);
1211 done:
1213 mutex_exit(&ph_impl->usba_ph_mutex);
1214 mutex_exit(&ph_data->p_mutex);
1216 if (timeout >= usba_drain_timeout) {
1217 int draining_succeeded;
1219 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1220 "timeout on draining requests, resetting pipe 0x%p",
1221 (void *)ph_impl);
1223 (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1224 USB_FLAGS_SLEEP);
1226 mutex_enter(&ph_data->p_mutex);
1227 draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1228 USB_CR_PIPE_RESET);
1229 /* this MUST have succeeded */
1230 ASSERT(draining_succeeded == USB_SUCCESS);
1231 mutex_exit(&ph_data->p_mutex);
1233 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1234 "draining requests done");
1237 if (usba_device->usb_hcdi_ops->usba_hcdi_pipe_close(ph_data,
1238 usb_flags) != USB_SUCCESS) {
1239 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1240 "usba_pipe_sync_close: hcd close failed");
1241 /* carry on regardless! */
1244 usba_destroy_pipe_handle(ph_data);
1246 return (USB_SUCCESS);
1251 * usb_pipe_set_private:
1252 * set private client date in the pipe handle
1255 usb_pipe_set_private(usb_pipe_handle_t pipe_handle, usb_opaque_t data)
1257 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1259 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1260 "usb_pipe_set_private: ");
1262 if (ph_data == NULL) {
1264 return (USB_INVALID_PIPE);
1266 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1267 usba_release_ph_data(ph_data->p_ph_impl);
1269 return (USB_INVALID_PERM);
1272 mutex_enter(&ph_data->p_mutex);
1273 ph_data->p_client_private = data;
1274 mutex_exit(&ph_data->p_mutex);
1276 usba_release_ph_data(ph_data->p_ph_impl);
1278 return (USB_SUCCESS);
1283 * usb_pipe_get_private:
1284 * get private client date from the pipe handle
1286 usb_opaque_t
1287 usb_pipe_get_private(usb_pipe_handle_t pipe_handle)
1289 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1290 usb_opaque_t data;
1292 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1293 "usb_pipe_get_private:");
1295 if (ph_data == NULL) {
1297 return (NULL);
1300 mutex_enter(&ph_data->p_mutex);
1301 data = ph_data->p_client_private;
1302 mutex_exit(&ph_data->p_mutex);
1304 usba_release_ph_data(ph_data->p_ph_impl);
1306 return (data);
1311 * usb_pipe_reset
1312 * Arguments:
1313 * dip - devinfo pointer
1314 * pipe_handle - opaque pipe handle
1315 * Returns:
1316 * USB_SUCCESS - pipe successfully reset or request queued
1317 * USB_FAILURE - undetermined failure
1318 * USB_INVALID_PIPE - pipe is invalid or already closed
1320 void
1321 usb_pipe_reset(dev_info_t *dip,
1322 usb_pipe_handle_t pipe_handle,
1323 usb_flags_t usb_flags,
1324 void (*callback)(
1325 usb_pipe_handle_t ph,
1326 usb_opaque_t arg,
1327 int rval,
1328 usb_cb_flags_t flags),
1329 usb_opaque_t callback_arg)
1331 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1332 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1333 usb_cb_flags_t callback_flags;
1335 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1336 "usb_pipe_reset: dip=0x%p ph=0x%p uf=0x%x",
1337 (void *)dip, (void *)pipe_handle, usb_flags);
1339 callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
1341 if ((dip == NULL) || (ph_data == NULL)) {
1342 if (callback) {
1343 callback(pipe_handle, callback_arg,
1344 USB_INVALID_ARGS, callback_flags);
1345 } else {
1346 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1347 usbai_log_handle,
1348 "usb_pipe_reset: invalid arguments");
1351 usba_release_ph_data(ph_impl);
1353 return;
1355 if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
1356 if (callback) {
1357 callback(pipe_handle, callback_arg,
1358 USB_INVALID_CONTEXT, callback_flags);
1359 } else {
1360 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1361 usbai_log_handle,
1362 "usb_pipe_reset: invalid context");
1365 usba_release_ph_data(ph_impl);
1367 return;
1370 mutex_enter(&ph_data->p_mutex);
1372 /* is this the default pipe? */
1373 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1374 if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
1375 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1376 "usb_pipe_reset: not allowed to reset def pipe");
1377 mutex_exit(&ph_data->p_mutex);
1379 if (callback) {
1380 callback(pipe_handle, callback_arg,
1381 USB_INVALID_PIPE, callback_flags);
1382 } else {
1383 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1384 usbai_log_handle,
1385 "usb_pipe_reset: invalid pipe");
1387 usba_release_ph_data(ph_impl);
1389 return;
1392 mutex_exit(&ph_data->p_mutex);
1394 (void) usba_pipe_setup_func_call(dip,
1395 usba_pipe_sync_reset, ph_impl, NULL, usb_flags, callback,
1396 callback_arg);
1400 /*ARGSUSED*/
1402 usba_pipe_sync_reset(dev_info_t *dip,
1403 usba_ph_impl_t *ph_impl,
1404 usba_pipe_async_req_t *request,
1405 usb_flags_t usb_flags)
1407 int rval, draining_succeeded;
1408 usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1409 ph_impl);
1410 usba_device_t *usba_device;
1412 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1413 "usba_pipe_sync_reset: dip=0x%p ph_data=0x%p uf=0x%x",
1414 (void *)dip, (void *)ph_data, usb_flags);
1416 mutex_enter(&ph_data->p_mutex);
1417 usba_device = ph_data->p_usba_device;
1418 mutex_exit(&ph_data->p_mutex);
1420 rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1421 usb_flags);
1422 mutex_enter(&ph_data->p_mutex);
1425 * The host controller has stopped polling of the endpoint.
1427 draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1428 USB_CR_PIPE_RESET);
1430 /* this MUST have succeeded */
1431 ASSERT(draining_succeeded == USB_SUCCESS);
1433 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1434 mutex_exit(&ph_data->p_mutex);
1437 * if there are requests still queued on the default pipe,
1438 * start them now
1440 usba_start_next_req(ph_data);
1442 usba_release_ph_data(ph_impl);
1444 return (rval);
1449 * usba_pipe_clear:
1450 * call hcd to clear pipe but don't wait for draining
1452 void
1453 usba_pipe_clear(usb_pipe_handle_t pipe_handle)
1455 usba_pipe_handle_data_t *ph_data = usba_get_ph_data(pipe_handle);
1456 usba_device_t *usba_device;
1457 usba_req_wrapper_t *req_wrp;
1458 int flush_requests = 1;
1460 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1461 "usba_pipe_clear: ph_data=0x%p", (void *)ph_data);
1463 if (ph_data == NULL) {
1465 return;
1468 mutex_enter(&ph_data->p_mutex);
1469 if (USBA_PIPE_CLOSING(usba_get_ph_state(ph_data))) {
1470 mutex_exit(&ph_data->p_mutex);
1472 return;
1474 usba_device = ph_data->p_usba_device;
1475 mutex_exit(&ph_data->p_mutex);
1477 (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1478 USB_FLAGS_SLEEP);
1480 mutex_enter(&ph_data->p_mutex);
1481 if (ph_data->p_dip) {
1482 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1483 USB_DPRINTF_L4(DPRINT_MASK_USBAI,
1484 usbai_log_handle,
1485 "no flushing on default pipe!");
1487 flush_requests = 0;
1491 if (flush_requests) {
1492 /* flush all requests in the pipehandle queue */
1493 while ((req_wrp = (usba_req_wrapper_t *)
1494 usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
1495 mutex_exit(&ph_data->p_mutex);
1496 usba_do_req_exc_cb(req_wrp, USB_CR_FLUSHED,
1497 USB_CB_RESET_PIPE);
1498 mutex_enter(&ph_data->p_mutex);
1502 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1503 mutex_exit(&ph_data->p_mutex);
1509 * usb_pipe_drain_reqs
1510 * this function blocks until there are no more requests
1511 * owned by this dip on the pipe
1513 * Arguments:
1514 * dip - devinfo pointer
1515 * pipe_handle - opaque pipe handle
1516 * timeout - timeout in seconds
1517 * flags - USB_FLAGS_SLEEP:
1518 * wait for completion.
1519 * cb - if USB_FLAGS_SLEEP has not been specified
1520 * this callback function will be called on
1521 * completion. This callback may be NULL
1522 * and no notification of completion will then
1523 * be provided.
1524 * cb_arg - 2nd argument to callback function.
1526 * callback and callback_arg should be NULL if USB_FLAGS_SLEEP has
1527 * been specified
1529 * Returns:
1530 * USB_SUCCESS - pipe successfully reset or request queued
1531 * USB_FAILURE - timeout
1532 * USB_* - refer to usbai.h
1535 usb_pipe_drain_reqs(dev_info_t *dip,
1536 usb_pipe_handle_t pipe_handle,
1537 uint_t time,
1538 usb_flags_t usb_flags,
1539 void (*cb)(
1540 usb_pipe_handle_t ph,
1541 usb_opaque_t arg, /* cb arg */
1542 int rval,
1543 usb_cb_flags_t flags),
1544 usb_opaque_t cb_arg)
1546 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1547 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1549 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1550 "usb_pipe_drain_reqs: dip=0x%p ph_data=0x%p tm=%d uf=0x%x",
1551 (void *)dip, (void *)ph_data, time, usb_flags);
1553 if (ph_data == NULL) {
1555 return (USB_INVALID_PIPE);
1557 if (dip == NULL) {
1558 usba_release_ph_data(ph_impl);
1560 return (USB_INVALID_ARGS);
1563 if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1564 usba_release_ph_data(ph_impl);
1566 return (USB_INVALID_CONTEXT);
1569 (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_drain_reqs,
1570 ph_impl, (usb_opaque_t)((uintptr_t)time), usb_flags, cb, cb_arg);
1572 return (USB_SUCCESS);
1577 * usba_pipe_sync_drain_reqs
1578 * this function blocks until there are no more requests
1579 * owned by this dip on the pipe
1581 * Arguments:
1582 * dip - devinfo pointer
1583 * ph_impl - pipe impl handle
1584 * timeout - timeout in seconds
1585 * Returns:
1586 * USB_SUCCESS - pipe successfully reset or request queued
1587 * USB_FAILURE - timeout
1588 * USB_* - see usbai.h
1590 /*ARGSUSED*/
1592 usba_pipe_sync_drain_reqs(dev_info_t *dip,
1593 usba_ph_impl_t *ph_impl,
1594 usba_pipe_async_req_t *request,
1595 usb_flags_t usb_flags)
1597 usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1598 ph_impl);
1599 int i;
1600 int timeout = 100 * (int)((uintptr_t)(request->arg));
1601 /* delay will be 10 ms */
1603 mutex_enter(&ph_data->p_mutex);
1605 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1606 "usba_pipe_sync_drain_reqs: "
1607 "dip=0x%p ph_data=0x%p timeout=%d ref=%d req=%d",
1608 (void *)dip, (void *)ph_data, timeout,
1609 usba_get_ph_ref_count(ph_data),
1610 ph_data->p_req_count);
1612 ASSERT(ph_data->p_req_count >= 0);
1615 * for default pipe, we need to check the active request
1616 * and the queue
1617 * Note that a pipe reset on the default pipe doesn't flush
1618 * the queue
1619 * for all other pipes we just check ref and req count since
1620 * these pipes are unshared
1622 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1623 for (i = 0; (i < timeout) || (request->arg == 0); i++) {
1624 usba_list_entry_t *next, *tmpnext;
1625 usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)
1626 ph_data->p_active_cntrl_req_wrp;
1627 int found = 0;
1628 int count = 0;
1630 /* active_req_wrp is only for control pipes */
1631 if ((req_wrp == NULL) || (req_wrp->wr_dip != dip)) {
1632 /* walk the queue */
1633 mutex_enter(&ph_data->p_queue.list_mutex);
1634 next = ph_data->p_queue.next;
1635 while (next != NULL) {
1636 mutex_enter(&next->list_mutex);
1637 req_wrp = (usba_req_wrapper_t *)
1638 next->private;
1639 found = (req_wrp->wr_dip == dip);
1640 if (found) {
1641 mutex_exit(&next->list_mutex);
1643 break;
1645 tmpnext = next->next;
1646 mutex_exit(&next->list_mutex);
1647 next = tmpnext;
1648 count++;
1650 mutex_exit(&ph_data->p_queue.list_mutex);
1651 if (found == 0) {
1652 break;
1656 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1657 "usb_pipe_sync_drain_reqs: "
1658 "cnt=%d active_req_wrp=0x%p",
1659 count, (void *)ph_data->p_active_cntrl_req_wrp);
1661 mutex_exit(&ph_data->p_mutex);
1662 delay(drv_usectohz(10000));
1663 mutex_enter(&ph_data->p_mutex);
1665 } else {
1666 mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
1667 for (i = 0; (i < timeout) || (request->arg == 0); i++) {
1668 ASSERT(ph_data->p_req_count >= 0);
1669 if (ph_data->p_req_count ||
1670 (ph_data->p_ph_impl->usba_ph_ref_count > 1)) {
1671 mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
1672 mutex_exit(&ph_data->p_mutex);
1673 delay(drv_usectohz(10000));
1674 mutex_enter(&ph_data->p_mutex);
1675 mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
1676 } else {
1677 break;
1680 mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
1683 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1684 "usb_pipe_sync_drain_reqs: timeout=%d active_req_wrp=0x%p req=%d",
1685 i, (void *)ph_data->p_active_cntrl_req_wrp, ph_data->p_req_count);
1687 mutex_exit(&ph_data->p_mutex);
1689 usba_release_ph_data(ph_impl);
1691 return (i >= timeout ? USB_FAILURE : USB_SUCCESS);
1696 * usba_persistent_pipe_open
1697 * Open all the pipes marked persistent for this device
1700 usba_persistent_pipe_open(usba_device_t *usba_device)
1702 usba_ph_impl_t *ph_impl;
1703 usb_pipe_handle_t pipe_handle;
1704 int i;
1705 int rval = USB_SUCCESS;
1707 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1708 "usba_persistent_pipe_open: usba_device=0x%p", (void *)usba_device);
1710 if (usba_device != NULL) {
1711 /* default pipe is the first one to be opened */
1712 mutex_enter(&usba_device->usb_mutex);
1713 for (i = 0; (rval == USB_SUCCESS) &&
1714 (i < USBA_N_ENDPOINTS); i++) {
1716 ph_impl = &usba_device->usb_ph_list[i];
1717 mutex_enter(&ph_impl->usba_ph_mutex);
1718 if (ph_impl->usba_ph_flags & USBA_PH_DATA_PERSISTENT) {
1719 ph_impl->usba_ph_flags &=
1720 ~USBA_PH_DATA_PERSISTENT;
1721 mutex_exit(&ph_impl->usba_ph_mutex);
1722 mutex_exit(&usba_device->usb_mutex);
1724 rval = usb_pipe_open(ph_impl->usba_ph_dip,
1725 &ph_impl->usba_ph_ep,
1726 &ph_impl->usba_ph_policy,
1727 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
1728 &pipe_handle);
1730 USB_DPRINTF_L3(DPRINT_MASK_USBAI,
1731 usbai_log_handle,
1732 "usba_persistent_pipe_open: "
1733 "ep_index=%d, rval=%d", i, rval);
1734 mutex_enter(&usba_device->usb_mutex);
1735 mutex_enter(&ph_impl->usba_ph_mutex);
1737 mutex_exit(&ph_impl->usba_ph_mutex);
1739 mutex_exit(&usba_device->usb_mutex);
1742 return (rval);
1747 * usba_persistent_pipe_close
1748 * Close all pipes of this device and mark them persistent
1750 void
1751 usba_persistent_pipe_close(usba_device_t *usba_device)
1753 usba_ph_impl_t *ph_impl;
1754 usb_pipe_handle_t pipe_handle;
1755 int i;
1757 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1758 "usba_persistent_pipe_close: usba_device=0x%p",
1759 (void *)usba_device);
1761 if (usba_device != NULL) {
1762 /* default pipe is the last one to be closed */
1763 mutex_enter(&usba_device->usb_mutex);
1765 for (i = (USBA_N_ENDPOINTS - 1); i >= 0; i--) {
1766 ph_impl = &usba_device->usb_ph_list[i];
1767 if (ph_impl->usba_ph_data != NULL) {
1768 mutex_enter(&ph_impl->usba_ph_mutex);
1769 ph_impl->usba_ph_flags |=
1770 USBA_PH_DATA_PERSISTENT;
1771 mutex_exit(&ph_impl->usba_ph_mutex);
1772 mutex_exit(&usba_device->usb_mutex);
1774 pipe_handle = (usb_pipe_handle_t)ph_impl;
1776 usb_pipe_close(ph_impl->usba_ph_dip,
1777 pipe_handle,
1778 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
1779 NULL, NULL);
1780 mutex_enter(&usba_device->usb_mutex);
1781 ASSERT(ph_impl->usba_ph_data == NULL);
1784 mutex_exit(&usba_device->usb_mutex);