5045 use atomic_{inc,dec}_* instead of atomic_add_*
[illumos-gate.git] / usr / src / uts / common / io / usb / usba / usbai_pipe_mgmt.c
blobe4d9c2bac806a3aaf81f27d33a93a628feb03f0c
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.
28 * USBA: Solaris USB Architecture support
30 * all functions exposed to client drivers have prefix usb_ while all USBA
31 * internal functions or functions exposed to HCD or hubd only have prefix
32 * usba_
34 * this file contains all USBAI pipe management
35 * usb_pipe_open()
36 * usb_pipe_close()
37 * usb_pipe_set_private()
38 * usb_pipe_get_private()
39 * usb_pipe_abort()
40 * usb_pipe_reset()
41 * usb_pipe_drain_reqs()
43 #define USBA_FRAMEWORK
44 #include <sys/usb/usba/usba_impl.h>
45 #include <sys/usb/usba/hcdi_impl.h>
46 #include <sys/atomic.h>
48 extern pri_t maxclsyspri;
49 extern pri_t minclsyspri;
51 /* function prototypes */
52 static void usba_pipe_do_async_func_thread(void *arg);
53 static int usba_pipe_sync_close(dev_info_t *, usba_ph_impl_t *,
54 usba_pipe_async_req_t *, usb_flags_t);
55 static int usba_pipe_sync_reset(dev_info_t *, usba_ph_impl_t *,
56 usba_pipe_async_req_t *, usb_flags_t);
57 static int usba_pipe_sync_drain_reqs(dev_info_t *, usba_ph_impl_t *,
58 usba_pipe_async_req_t *, usb_flags_t);
60 /* local tunables */
61 int usba_drain_timeout = 1000; /* in ms */
63 /* return the default pipe for this device */
64 usb_pipe_handle_t
65 usba_get_dflt_pipe_handle(dev_info_t *dip)
67 usba_device_t *usba_device;
68 usb_pipe_handle_t pipe_handle = NULL;
70 if (dip) {
71 usba_device = usba_get_usba_device(dip);
72 if (usba_device) {
73 pipe_handle =
74 (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
78 return (pipe_handle);
82 /* return dip owner of pipe_handle */
83 dev_info_t *
84 usba_get_dip(usb_pipe_handle_t pipe_handle)
86 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
87 dev_info_t *dip = NULL;
89 if (ph_impl) {
90 mutex_enter(&ph_impl->usba_ph_mutex);
91 dip = ph_impl->usba_ph_dip;
92 mutex_exit(&ph_impl->usba_ph_mutex);
95 return (dip);
99 usb_pipe_handle_t
100 usba_usbdev_to_dflt_pipe_handle(usba_device_t *usba_device)
102 usb_pipe_handle_t pipe_handle = NULL;
104 if ((usba_device) &&
105 (usba_device->usb_ph_list[0].usba_ph_data != NULL)) {
106 pipe_handle = (usb_pipe_handle_t)&usba_device->usb_ph_list[0];
109 return (pipe_handle);
113 usba_pipe_handle_data_t *
114 usba_get_ph_data(usb_pipe_handle_t pipe_handle)
116 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
117 usba_pipe_handle_data_t *ph_data = NULL;
119 if (ph_impl) {
120 mutex_enter(&ph_impl->usba_ph_mutex);
121 ASSERT(ph_impl->usba_ph_ref_count >= 0);
122 ph_data = ph_impl->usba_ph_data;
123 mutex_exit(&ph_impl->usba_ph_mutex);
126 return (ph_data);
130 usb_pipe_handle_t
131 usba_get_pipe_handle(usba_pipe_handle_data_t *ph_data)
133 usb_pipe_handle_t ph = NULL;
135 if (ph_data) {
136 mutex_enter(&ph_data->p_mutex);
137 ASSERT(ph_data->p_req_count >= 0);
138 ph = (usb_pipe_handle_t)ph_data->p_ph_impl;
139 mutex_exit(&ph_data->p_mutex);
142 return (ph);
147 * opaque to pipe handle impl translation with incr of ref count. The caller
148 * must release ph_data when done. Increment the ref count ensures that
149 * the ph_data will not be freed underneath us.
151 usba_pipe_handle_data_t *
152 usba_hold_ph_data(usb_pipe_handle_t pipe_handle)
154 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
155 usba_pipe_handle_data_t *ph_data = NULL;
157 if (ph_impl) {
158 mutex_enter(&ph_impl->usba_ph_mutex);
160 switch (ph_impl->usba_ph_state) {
161 case USB_PIPE_STATE_IDLE:
162 case USB_PIPE_STATE_ACTIVE:
163 case USB_PIPE_STATE_ERROR:
164 ph_data = ph_impl->usba_ph_data;
165 ph_impl->usba_ph_ref_count++;
166 break;
167 case USB_PIPE_STATE_CLOSED:
168 case USB_PIPE_STATE_CLOSING:
169 default:
170 break;
173 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
174 "usba_hold_ph_data: ph_impl=0x%p state=%d ref=%d",
175 (void *)ph_impl, ph_impl->usba_ph_state,
176 ph_impl->usba_ph_ref_count);
178 mutex_exit(&ph_impl->usba_ph_mutex);
181 return (ph_data);
185 void
186 usba_release_ph_data(usba_ph_impl_t *ph_impl)
188 if (ph_impl) {
189 mutex_enter(&ph_impl->usba_ph_mutex);
191 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
192 "usba_release_ph_data: "
193 "ph_impl=0x%p state=%d ref=%d",
194 (void *)ph_impl, ph_impl->usba_ph_state,
195 ph_impl->usba_ph_ref_count);
197 #ifndef __lock_lint
198 if (ph_impl->usba_ph_data) {
199 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
200 "usba_release_ph_data: req_count=%d",
201 ph_impl->usba_ph_data->p_req_count);
202 ASSERT(ph_impl->usba_ph_data->p_req_count >= 0);
204 #endif
205 ph_impl->usba_ph_ref_count--;
206 ASSERT(ph_impl->usba_ph_ref_count >= 0);
208 mutex_exit(&ph_impl->usba_ph_mutex);
214 * get pipe state from ph_data
216 usb_pipe_state_t
217 usba_get_ph_state(usba_pipe_handle_data_t *ph_data)
219 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
220 usb_pipe_state_t pipe_state;
222 ASSERT(mutex_owned(&ph_data->p_mutex));
223 mutex_enter(&ph_impl->usba_ph_mutex);
224 pipe_state = ph_impl->usba_ph_state;
225 mutex_exit(&ph_impl->usba_ph_mutex);
227 return (pipe_state);
232 * get ref_count from ph_data
235 usba_get_ph_ref_count(usba_pipe_handle_data_t *ph_data)
237 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
238 int ref_count;
240 mutex_enter(&ph_impl->usba_ph_mutex);
241 ref_count = ph_impl->usba_ph_ref_count;
242 mutex_exit(&ph_impl->usba_ph_mutex);
244 return (ref_count);
249 * new pipe state
250 * We need to hold both pipe mutex and ph_impl mutex
252 void
253 usba_pipe_new_state(usba_pipe_handle_data_t *ph_data, usb_pipe_state_t state)
255 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
257 ASSERT(mutex_owned(&ph_data->p_mutex));
259 mutex_enter(&ph_impl->usba_ph_mutex);
260 ASSERT(ph_data->p_req_count >= 0);
261 ASSERT(ph_impl->usba_ph_ref_count >= 0);
263 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
264 "usba_pipe_new_state: "
265 "ph_data=0x%p old=%s new=%s ref=%d req=%d",
266 (void *)ph_data, usb_str_pipe_state(ph_impl->usba_ph_state),
267 usb_str_pipe_state(state),
268 ph_impl->usba_ph_ref_count, ph_data->p_req_count);
270 switch (ph_impl->usba_ph_state) {
271 case USB_PIPE_STATE_IDLE:
272 case USB_PIPE_STATE_ACTIVE:
273 case USB_PIPE_STATE_ERROR:
274 case USB_PIPE_STATE_CLOSED:
275 ph_impl->usba_ph_state = state;
276 break;
277 case USB_PIPE_STATE_CLOSING:
278 default:
279 break;
281 mutex_exit(&ph_impl->usba_ph_mutex);
286 * async function execution support
287 * Arguments:
288 * dip - devinfo pointer
289 * sync_func - function to be executed
290 * ph_impl - impl pipehandle
291 * arg - opaque arg
292 * usb_flags - none
293 * callback - function to be called on completion, may be NULL
294 * callback_arg - argument for callback function
296 * Note: The caller must do a hold on ph_data
297 * We sleep for memory resources and taskq_dispatch which will ensure
298 * that this function succeeds
301 usba_pipe_setup_func_call(
302 dev_info_t *dip,
303 int (*sync_func)(dev_info_t *,
304 usba_ph_impl_t *, usba_pipe_async_req_t *,
305 usb_flags_t),
306 usba_ph_impl_t *ph_impl,
307 usb_opaque_t arg,
308 usb_flags_t usb_flags,
309 void (*callback)(usb_pipe_handle_t,
310 usb_opaque_t, int, usb_cb_flags_t),
311 usb_opaque_t callback_arg)
313 usba_pipe_async_req_t *request;
314 usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl;
315 usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
316 int rval = USB_SUCCESS;
317 usb_cb_flags_t callback_flags;
319 USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
320 "usba_pipe_setup_func_call: ph_impl=0x%p, func=0x%p",
321 (void *)ph_impl, (void *)sync_func);
323 if (((usb_flags & USB_FLAGS_SLEEP) == 0) && (callback == NULL)) {
324 usba_release_ph_data(ph_impl);
325 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
326 "usba_pipe_setup_func_call: async request with "
327 "no callback");
329 return (USB_INVALID_ARGS);
332 request = kmem_zalloc(sizeof (usba_pipe_async_req_t), KM_SLEEP);
333 request->dip = dip;
334 request->ph_impl = ph_impl;
335 request->arg = arg;
338 * OR in sleep flag. regardless of calling sync_func directly
339 * or in a new thread, we will always wait for completion
341 request->usb_flags = usb_flags | USB_FLAGS_SLEEP;
342 request->sync_func = sync_func;
343 request->callback = callback;
344 request->callback_arg = callback_arg;
346 if (usb_flags & USB_FLAGS_SLEEP) {
347 rval = sync_func(dip, ph_impl, request, usb_flags);
348 kmem_free(request, sizeof (usba_pipe_async_req_t));
350 } else if (usba_async_ph_req(ph_data,
351 usba_pipe_do_async_func_thread,
352 (void *)request, USB_FLAGS_SLEEP) != USB_SUCCESS) {
353 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
354 "usb_async_req failed: ph_impl=0x%p, func=0x%p",
355 (void *)ph_impl, (void *)sync_func);
357 if (callback) {
358 callback_flags =
359 usba_check_intr_context(USB_CB_ASYNC_REQ_FAILED);
360 callback(pipe_handle, callback_arg, USB_FAILURE,
361 callback_flags);
364 kmem_free(request, sizeof (usba_pipe_async_req_t));
365 usba_release_ph_data(ph_impl);
368 return (rval);
373 * taskq thread function to execute function synchronously
374 * Note: caller must have done a hold on ph_data
376 static void
377 usba_pipe_do_async_func_thread(void *arg)
379 usba_pipe_async_req_t *request = (usba_pipe_async_req_t *)arg;
380 usba_ph_impl_t *ph_impl = request->ph_impl;
381 usb_pipe_handle_t pipe_handle = (usb_pipe_handle_t)ph_impl;
382 int rval;
383 usb_cb_flags_t cb_flags = USB_CB_NO_INFO;
385 if ((rval = request->sync_func(request->dip, ph_impl,
386 request, request->usb_flags | USB_FLAGS_SLEEP)) !=
387 USB_SUCCESS) {
388 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
389 "sync func failed (%d)", rval);
392 if (request->callback) {
393 request->callback(pipe_handle, request->callback_arg, rval,
394 cb_flags);
397 kmem_free(request, sizeof (usba_pipe_async_req_t));
402 * default endpoint descriptor and pipe policy
404 usb_ep_descr_t usba_default_ep_descr =
405 {7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0};
407 /* set some meaningful defaults */
408 static usb_pipe_policy_t usba_default_ep_pipe_policy = {3};
412 * usb_get_ep_index: create an index from endpoint address that can
413 * be used to index into endpoint pipe lists
415 uchar_t
416 usb_get_ep_index(uint8_t ep_addr)
418 return ((ep_addr & USB_EP_NUM_MASK) +
419 ((ep_addr & USB_EP_DIR_MASK) ? 16 : 0));
424 * pipe management
425 * utility functions to init and destroy a pipehandle
427 static int
428 usba_init_pipe_handle(dev_info_t *dip,
429 usba_device_t *usba_device,
430 usb_ep_descr_t *ep,
431 usb_pipe_policy_t *pipe_policy,
432 usba_ph_impl_t *ph_impl)
434 int instance = ddi_get_instance(dip);
435 unsigned int def_instance = instance;
436 static unsigned int anon_instance = 0;
437 char tq_name[TASKQ_NAMELEN];
439 usba_pipe_handle_data_t *ph_data = ph_impl->usba_ph_data;
440 ddi_iblock_cookie_t iblock_cookie =
441 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
442 hcdi_iblock_cookie;
444 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
445 "usba_init_pipe_handle: "
446 "usba_device=0x%p ep=0x%x", (void *)usba_device,
447 ep->bEndpointAddress);
448 mutex_init(&ph_data->p_mutex, NULL, MUTEX_DRIVER, iblock_cookie);
450 /* just to keep warlock happy, there is no contention yet */
451 mutex_enter(&ph_data->p_mutex);
452 mutex_enter(&usba_device->usb_mutex);
454 ASSERT(pipe_policy->pp_max_async_reqs);
456 if (instance != -1) {
457 (void) snprintf(tq_name, sizeof (tq_name),
458 "USB_%s_%x_pipehndl_tq_%d",
459 ddi_driver_name(dip), ep->bEndpointAddress, instance);
460 } else {
461 def_instance = atomic_inc_32_nv(&anon_instance);
463 (void) snprintf(tq_name, sizeof (tq_name),
464 "USB_%s_%x_pipehndl_tq_%d_",
465 ddi_driver_name(dip), ep->bEndpointAddress, def_instance);
468 ph_data->p_taskq = taskq_create(tq_name,
469 pipe_policy->pp_max_async_reqs + 1,
470 ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
471 USB_EP_ATTR_ISOCH) ?
472 (maxclsyspri - 5) : minclsyspri,
473 2 * (pipe_policy->pp_max_async_reqs + 1),
474 8 * (pipe_policy->pp_max_async_reqs + 1),
475 TASKQ_PREPOPULATE);
478 * Create a shared taskq.
480 if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
481 int iface = usb_get_if_number(dip);
482 if (iface < 0) {
483 /* we own the device, use first entry */
484 iface = 0;
487 if (instance != -1) {
488 (void) snprintf(tq_name, sizeof (tq_name),
489 "USB_%s_%x_shared_tq_%d",
490 ddi_driver_name(dip), ep->bEndpointAddress,
491 instance);
492 } else {
493 (void) snprintf(tq_name, sizeof (tq_name),
494 "USB_%s_%x_shared_tq_%d_",
495 ddi_driver_name(dip), ep->bEndpointAddress,
496 def_instance);
499 if (usba_device->usb_shared_taskq_ref_count[iface] == 0) {
500 usba_device->usb_shared_taskq[iface] =
501 taskq_create(tq_name,
502 1, /* Number threads. */
503 maxclsyspri - 5, /* Priority */
504 1, /* minalloc */
505 USBA_N_ENDPOINTS + 4, /* maxalloc */
506 TASKQ_PREPOPULATE);
507 ASSERT(usba_device->usb_shared_taskq[iface] != NULL);
509 usba_device->usb_shared_taskq_ref_count[iface]++;
512 ph_data->p_dip = dip;
513 ph_data->p_usba_device = usba_device;
514 ph_data->p_ep = *ep;
515 ph_data->p_ph_impl = ph_impl;
516 if ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
517 USB_EP_ATTR_ISOCH) {
518 ph_data->p_spec_flag |= USBA_PH_FLAG_USE_SOFT_INTR;
521 /* fix up the MaxPacketSize if it is the default endpoint descr */
522 if ((ep == &usba_default_ep_descr) && usba_device) {
523 uint16_t maxpktsize;
525 maxpktsize = usba_device->usb_dev_descr->bMaxPacketSize0;
526 if (usba_device->usb_is_wireless) {
528 * according to wusb 1.0 spec 4.8.1, the host must
529 * assume a wMaxPacketSize of 512 for the default
530 * control pipe of a wusb device
532 maxpktsize = 0x200;
534 USB_DPRINTF_L3(DPRINT_MASK_USBAI, usbai_log_handle,
535 "adjusting max packet size from %d to %d",
536 ph_data->p_ep.wMaxPacketSize, maxpktsize);
538 ph_data->p_ep.wMaxPacketSize = maxpktsize;
541 /* now update usba_ph_impl structure */
542 mutex_enter(&ph_impl->usba_ph_mutex);
543 ph_impl->usba_ph_dip = dip;
544 ph_impl->usba_ph_ep = ph_data->p_ep;
545 ph_impl->usba_ph_policy = ph_data->p_policy = *pipe_policy;
546 mutex_exit(&ph_impl->usba_ph_mutex);
548 usba_init_list(&ph_data->p_queue, (usb_opaque_t)ph_data, iblock_cookie);
549 usba_init_list(&ph_data->p_cb_queue, (usb_opaque_t)ph_data,
550 iblock_cookie);
551 mutex_exit(&usba_device->usb_mutex);
552 mutex_exit(&ph_data->p_mutex);
554 return (USB_SUCCESS);
558 static void
559 usba_taskq_destroy(void *arg)
561 taskq_destroy((taskq_t *)arg);
565 static void
566 usba_destroy_pipe_handle(usba_pipe_handle_data_t *ph_data)
568 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
569 int timeout;
570 usba_device_t *usba_device;
572 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
573 "usba_destroy_pipe_handle: ph_data=0x%p", (void *)ph_data);
575 mutex_enter(&ph_data->p_mutex);
576 mutex_enter(&ph_impl->usba_ph_mutex);
578 /* check for all activity to drain */
579 for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
580 if ((ph_impl->usba_ph_ref_count <= 1) &&
581 (ph_data->p_req_count == 0)) {
583 break;
585 mutex_exit(&ph_data->p_mutex);
586 mutex_exit(&ph_impl->usba_ph_mutex);
587 delay(drv_usectohz(1000));
588 mutex_enter(&ph_data->p_mutex);
589 mutex_enter(&ph_impl->usba_ph_mutex);
593 * set state to closed here so any other thread
594 * that is waiting for the CLOSED state will
595 * continue. Otherwise, taskq_destroy might deadlock
597 ph_impl->usba_ph_data = NULL;
598 ph_impl->usba_ph_ref_count = 0;
599 ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSED;
601 if (ph_data->p_taskq) {
602 mutex_exit(&ph_data->p_mutex);
603 mutex_exit(&ph_impl->usba_ph_mutex);
604 if (taskq_member(ph_data->p_taskq, curthread)) {
606 * use system taskq to destroy ph's taskq to avoid
607 * deadlock
609 (void) taskq_dispatch(system_taskq,
610 usba_taskq_destroy, ph_data->p_taskq, TQ_SLEEP);
611 } else {
612 taskq_destroy(ph_data->p_taskq);
614 } else {
615 mutex_exit(&ph_data->p_mutex);
616 mutex_exit(&ph_impl->usba_ph_mutex);
619 usba_device = ph_data->p_usba_device;
620 mutex_enter(&ph_data->p_mutex);
621 if (ph_data->p_spec_flag & USBA_PH_FLAG_TQ_SHARE) {
622 int iface = usb_get_if_number(ph_data->p_dip);
623 if (iface < 0) {
624 /* we own the device, use the first entry */
625 iface = 0;
627 mutex_enter(&usba_device->usb_mutex);
628 if (--usba_device->usb_shared_taskq_ref_count[iface] == 0) {
629 ph_data->p_spec_flag &= ~USBA_PH_FLAG_TQ_SHARE;
630 if (taskq_member(usba_device->usb_shared_taskq[iface],
631 curthread)) {
632 (void) taskq_dispatch(
633 system_taskq,
634 usba_taskq_destroy,
635 usba_device->usb_shared_taskq[iface],
636 TQ_SLEEP);
637 } else {
638 taskq_destroy(
639 usba_device->usb_shared_taskq[iface]);
642 mutex_exit(&usba_device->usb_mutex);
644 mutex_exit(&ph_data->p_mutex);
647 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
648 "usba_destroy_pipe_handle: destroying ph_data=0x%p",
649 (void *)ph_data);
651 usba_destroy_list(&ph_data->p_queue);
652 usba_destroy_list(&ph_data->p_cb_queue);
654 /* destroy mutexes */
655 mutex_destroy(&ph_data->p_mutex);
657 kmem_free(ph_data, sizeof (usba_pipe_handle_data_t));
662 * usba_drain_cbs:
663 * Drain the request callbacks on the pipe handle
666 usba_drain_cbs(usba_pipe_handle_data_t *ph_data, usb_cb_flags_t cb_flags,
667 usb_cr_t cr)
669 usba_req_wrapper_t *req_wrp;
670 int flush_requests = 1;
671 usba_ph_impl_t *ph_impl = ph_data->p_ph_impl;
672 int timeout;
673 int rval = USB_SUCCESS;
675 ASSERT(mutex_owned(&ph_data->p_mutex));
677 mutex_enter(&ph_impl->usba_ph_mutex);
678 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
679 "usba_drain_cbs: ph_data=0x%p ref=%d req=%d cb=0x%x cr=%d",
680 (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count,
681 cb_flags, cr);
682 ASSERT(ph_data->p_req_count >= 0);
683 mutex_exit(&ph_impl->usba_ph_mutex);
685 if (ph_data->p_dip) {
686 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
687 USB_DPRINTF_L4(DPRINT_MASK_USBAI,
688 usbai_log_handle,
689 "no flushing on default pipe!");
691 flush_requests = 0;
695 if (flush_requests) {
696 /* flush all requests in the pipehandle queue */
697 while ((req_wrp = (usba_req_wrapper_t *)
698 usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
699 mutex_exit(&ph_data->p_mutex);
700 usba_do_req_exc_cb(req_wrp, cr, cb_flags);
701 mutex_enter(&ph_data->p_mutex);
706 * wait for any callbacks in progress but don't wait for
707 * for queued requests on the default pipe
709 for (timeout = 0; (timeout < usba_drain_timeout) &&
710 (ph_data->p_req_count >
711 usba_list_entry_count(&ph_data->p_queue));
712 timeout++) {
713 mutex_exit(&ph_data->p_mutex);
714 delay(drv_usectohz(1000));
715 mutex_enter(&ph_data->p_mutex);
718 mutex_enter(&ph_impl->usba_ph_mutex);
719 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
720 "usba_drain_cbs done: ph_data=0x%p ref=%d req=%d",
721 (void *)ph_data, ph_impl->usba_ph_ref_count, ph_data->p_req_count);
722 mutex_exit(&ph_impl->usba_ph_mutex);
724 if (timeout == usba_drain_timeout) {
725 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
726 "draining callbacks timed out!");
728 rval = USB_FAILURE;
731 return (rval);
736 * usb_pipe_open():
738 * Before using any pipe including the default pipe, it should be opened
739 * using usb_pipe_open(). On a successful open, a pipe handle is returned
740 * for use in other usb_pipe_*() functions
742 * The default pipe can only be opened by the hub driver
744 * The bandwidth has been allocated and guaranteed on successful
745 * opening of an isoc/intr pipes.
747 * Only the default pipe can be shared. all other control pipes
748 * are excusively opened by default.
749 * A pipe policy and endpoint descriptor must always be provided
750 * except for default pipe
752 * Arguments:
753 * dip - devinfo ptr
754 * ep - endpoint descriptor pointer
755 * pipe_policy - pointer to pipe policy which provides hints on how
756 * the pipe will be used.
757 * flags - USB_FLAGS_SLEEP wait for resources
758 * to become available
759 * pipe_handle - a pipe handle pointer. On a successful open,
760 * a pipe_handle is returned in this pointer.
762 * Return values:
763 * USB_SUCCESS - open succeeded
764 * USB_FAILURE - unspecified open failure or pipe is already open
765 * USB_NO_RESOURCES - no resources were available to complete the open
766 * USB_NO_BANDWIDTH - no bandwidth available (isoc/intr pipes)
767 * USB_* - refer to usbai.h
770 usb_pipe_open(
771 dev_info_t *dip,
772 usb_ep_descr_t *ep,
773 usb_pipe_policy_t *pipe_policy,
774 usb_flags_t usb_flags,
775 usb_pipe_handle_t *pipe_handle)
777 usba_device_t *usba_device;
778 int rval;
779 usba_pipe_handle_data_t *ph_data;
780 usba_ph_impl_t *ph_impl;
781 uchar_t ep_index;
782 int kmflag;
783 size_t size;
785 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
786 "usb_pipe_open:\n\t"
787 "dip=0x%p ep=0x%p pp=0x%p uf=0x%x ph=0x%p",
788 (void *)dip, (void *)ep, (void *)pipe_policy, usb_flags,
789 (void *)pipe_handle);
791 if ((dip == NULL) || (pipe_handle == NULL)) {
793 return (USB_INVALID_ARGS);
796 if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
798 return (USB_INVALID_CONTEXT);
800 usba_device = usba_get_usba_device(dip);
802 if ((ep != NULL) && (pipe_policy == NULL)) {
803 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
804 "usb_pipe_open: null pipe policy");
806 return (USB_INVALID_ARGS);
809 /* is the device still connected? */
810 if ((ep != NULL) & DEVI_IS_DEVICE_REMOVED(dip)) {
811 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
812 "usb_pipe_open: device has been removed");
814 return (USB_FAILURE);
819 * if a null endpoint pointer was passed, use the default
820 * endpoint descriptor
822 if (ep == NULL) {
823 if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
824 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
825 "usb_pipe_open: not allowed to open def pipe");
827 return (USB_INVALID_PERM);
830 ep = &usba_default_ep_descr;
831 pipe_policy = &usba_default_ep_pipe_policy;
834 if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
835 if (((ep->bmAttributes & USB_EP_ATTR_MASK) ==
836 USB_EP_ATTR_CONTROL) ||
837 ((ep->bmAttributes & USB_EP_ATTR_MASK) ==
838 USB_EP_ATTR_ISOCH)) {
839 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
840 "usb_pipe_open: shared taskq not allowed with "
841 "ctrl or isoch pipe");
843 return (USB_INVALID_ARGS);
847 kmflag = (usb_flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
848 size = sizeof (usba_pipe_handle_data_t);
850 if ((ph_data = kmem_zalloc(size, kmflag)) == NULL) {
852 return (USB_NO_RESOURCES);
855 /* check if pipe is already open and if so fail */
856 ep_index = usb_get_ep_index(ep->bEndpointAddress);
857 ph_impl = &usba_device->usb_ph_list[ep_index];
859 mutex_enter(&usba_device->usb_mutex);
860 mutex_enter(&ph_impl->usba_ph_mutex);
862 if (ph_impl->usba_ph_data) {
863 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
864 "usb_pipe_open: pipe to ep %d already open", ep_index);
865 mutex_exit(&ph_impl->usba_ph_mutex);
866 mutex_exit(&usba_device->usb_mutex);
867 kmem_free(ph_data, size);
869 return (USB_BUSY);
872 ph_impl->usba_ph_data = ph_data;
874 mutex_exit(&ph_impl->usba_ph_mutex);
875 mutex_exit(&usba_device->usb_mutex);
877 if (usb_flags & USB_FLAGS_SERIALIZED_CB) {
878 mutex_enter(&ph_data->p_mutex);
879 ph_data->p_spec_flag |= USBA_PH_FLAG_TQ_SHARE;
880 mutex_exit(&ph_data->p_mutex);
884 * allocate and initialize the pipe handle
886 if ((rval = usba_init_pipe_handle(dip, usba_device,
887 ep, pipe_policy, ph_impl)) != USB_SUCCESS) {
888 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
889 "usb_pipe_open: pipe init failed (%d)", rval);
891 return (rval);
893 ph_data = ph_impl->usba_ph_data;
896 * ask the hcd to open the pipe
898 if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_open(ph_data,
899 usb_flags)) != USB_SUCCESS) {
900 usba_destroy_pipe_handle(ph_data);
902 *pipe_handle = NULL;
903 } else {
904 *pipe_handle = (usb_pipe_handle_t)ph_impl;
906 /* set the pipe state after a successful hcd open */
907 mutex_enter(&ph_data->p_mutex);
908 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
909 mutex_exit(&ph_data->p_mutex);
912 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
913 "usb_pipe_open: ph_impl=0x%p (0x%p)",
914 (void *)ph_impl, (void *)ph_data);
916 return (rval);
921 * usb_pipe_close/sync_close:
923 * Close a pipe and release all resources and free the pipe_handle.
924 * Automatic polling, if active, will be terminated
926 * Arguments:
927 * dip - devinfo ptr
928 * pipehandle - pointer to pipehandle. The pipehandle will be
929 * zeroed on successful completion
930 * flags - USB_FLAGS_SLEEP:
931 * wait for resources, pipe
932 * to become free, all callbacks completed
933 * callback - If USB_FLAGS_SLEEP has not been specified, a
934 * callback will be performed.
935 * callback_arg - the first argument of the callback. Note that
936 * the pipehandle will be zeroed and not passed
938 * Notes:
939 * Pipe close will always succeed regardless whether USB_FLAGS_SLEEP has been
940 * specified or not.
941 * An async close will always succeed if the hint in the pipe policy
942 * has been correct about the max number of async taskq requests required.
943 * If there are really no resources, the pipe handle will be linked into
944 * a garbage pipe list and periodically checked by USBA until it can be
945 * closed. This may cause a hang in the detach of the driver.
946 * USBA will prevent the client from submitting more requests to a pipe
947 * that is being closed
948 * Subsequent usb_pipe_close() requests on the same pipe to USBA will
949 * wait for the previous close(s) to finish.
951 * Note that once we start closing a pipe, we cannot go back anymore
952 * to a normal pipe state
954 void
955 usb_pipe_close(dev_info_t *dip,
956 usb_pipe_handle_t pipe_handle,
957 usb_flags_t usb_flags,
958 void (*callback)(
959 usb_pipe_handle_t pipe_handle,
960 usb_opaque_t arg,
961 int rval,
962 usb_cb_flags_t flags),
963 usb_opaque_t callback_arg)
965 usba_pipe_handle_data_t *ph_data;
966 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
967 usb_cb_flags_t callback_flags;
969 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
970 "usb_pipe_close: ph=0x%p", (void *)pipe_handle);
972 callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
973 if ((dip == NULL) || (pipe_handle == NULL)) {
974 if (callback) {
975 callback(pipe_handle, callback_arg,
976 USB_INVALID_ARGS, callback_flags);
977 } else {
978 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
979 usbai_log_handle,
980 "usb_pipe_close: invalid arguments");
983 return;
986 if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
988 * It is the client driver doing the pipe close,
989 * the pipe is no longer persistent then.
991 mutex_enter(&ph_impl->usba_ph_mutex);
992 ph_impl->usba_ph_flags &= ~USBA_PH_DATA_PERSISTENT;
993 mutex_exit(&ph_impl->usba_ph_mutex);
996 if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
997 if (callback) {
998 callback(pipe_handle, callback_arg,
999 USB_INVALID_CONTEXT, callback_flags);
1000 } else {
1001 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1002 usbai_log_handle,
1003 "usb_pipe_close: invalid context");
1006 return;
1009 if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
1011 /* hold pipehandle anyways since we will decrement later */
1012 mutex_enter(&ph_impl->usba_ph_mutex);
1013 ph_impl->usba_ph_ref_count++;
1014 mutex_exit(&ph_impl->usba_ph_mutex);
1016 (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
1017 ph_impl, NULL, usb_flags, callback, callback_arg);
1019 return;
1022 mutex_enter(&ph_data->p_mutex);
1024 if (USBA_IS_DEFAULT_PIPE(ph_data) &&
1025 ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0)) {
1026 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1027 "usb_pipe_close: not allowed to close def pipe");
1028 mutex_exit(&ph_data->p_mutex);
1030 usba_release_ph_data(ph_impl);
1032 if (callback) {
1033 callback(pipe_handle, callback_arg,
1034 USB_INVALID_PIPE, callback_flags);
1035 } else {
1036 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1037 usbai_log_handle,
1038 "usb_pipe_close: invalid pipe");
1041 return;
1044 mutex_exit(&ph_data->p_mutex);
1046 (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_close,
1047 ph_impl, NULL, usb_flags, callback, callback_arg);
1051 /*ARGSUSED*/
1052 static int
1053 usba_pipe_sync_close(dev_info_t *dip, usba_ph_impl_t *ph_impl,
1054 usba_pipe_async_req_t *request, usb_flags_t usb_flags)
1056 usba_device_t *usba_device;
1057 usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
1058 (usb_pipe_handle_t)ph_impl);
1059 int attribute;
1060 uchar_t dir;
1061 int timeout;
1063 if (ph_impl == NULL) {
1065 return (USB_SUCCESS);
1068 mutex_enter(&ph_impl->usba_ph_mutex);
1069 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1070 "usba_pipe_sync_close: dip=0x%p ph_data=0x%p state=%d ref=%d",
1071 (void *)dip, (void *)ph_data, ph_impl->usba_ph_state,
1072 ph_impl->usba_ph_ref_count);
1075 * if another thread opens the pipe again, this loop could
1076 * be truly forever
1078 if ((ph_data == NULL) ||
1079 (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSING) ||
1080 (ph_impl->usba_ph_state == USB_PIPE_STATE_CLOSED)) {
1081 /* wait forever till really closed */
1082 mutex_exit(&ph_impl->usba_ph_mutex);
1083 usba_release_ph_data(ph_impl);
1085 while (usba_get_ph_data((usb_pipe_handle_t)ph_impl)) {
1086 delay(1);
1089 return (USB_SUCCESS);
1091 ph_impl->usba_ph_state = USB_PIPE_STATE_CLOSING;
1092 mutex_exit(&ph_impl->usba_ph_mutex);
1094 mutex_enter(&ph_data->p_mutex);
1095 mutex_enter(&ph_impl->usba_ph_mutex);
1097 attribute = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
1098 dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
1100 usba_device = ph_data->p_usba_device;
1103 * For control and bulk, we will drain till ref_count <= 1 and
1104 * req_count == 0 but for isoc and intr IN, we can only wait
1105 * till the ref_count === 1 as the req_count will never go to 0
1107 for (timeout = 0; timeout < usba_drain_timeout; timeout++) {
1108 switch (attribute) {
1109 case USB_EP_ATTR_CONTROL:
1110 case USB_EP_ATTR_BULK:
1111 if ((ph_data->p_req_count == 0) &&
1112 (ph_impl->usba_ph_ref_count <= 1)) {
1113 goto done;
1115 break;
1116 case USB_EP_ATTR_INTR:
1117 case USB_EP_ATTR_ISOCH:
1118 if (dir == USB_EP_DIR_IN) {
1119 if (ph_impl->usba_ph_ref_count <= 1) {
1120 goto done;
1122 } else if ((ph_data->p_req_count == 0) &&
1123 (ph_impl->usba_ph_ref_count <= 1)) {
1124 goto done;
1126 break;
1128 mutex_exit(&ph_impl->usba_ph_mutex);
1129 mutex_exit(&ph_data->p_mutex);
1130 delay(drv_usectohz(1000));
1131 mutex_enter(&ph_data->p_mutex);
1132 mutex_enter(&ph_impl->usba_ph_mutex);
1134 done:
1136 mutex_exit(&ph_impl->usba_ph_mutex);
1137 mutex_exit(&ph_data->p_mutex);
1139 if (timeout >= usba_drain_timeout) {
1140 int draining_succeeded;
1142 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1143 "timeout on draining requests, resetting pipe 0x%p",
1144 (void *)ph_impl);
1146 (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1147 USB_FLAGS_SLEEP);
1149 mutex_enter(&ph_data->p_mutex);
1150 draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1151 USB_CR_PIPE_RESET);
1152 /* this MUST have succeeded */
1153 ASSERT(draining_succeeded == USB_SUCCESS);
1154 mutex_exit(&ph_data->p_mutex);
1156 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1157 "draining requests done");
1160 if (usba_device->usb_hcdi_ops->usba_hcdi_pipe_close(ph_data,
1161 usb_flags) != USB_SUCCESS) {
1162 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1163 "usba_pipe_sync_close: hcd close failed");
1164 /* carry on regardless! */
1167 usba_destroy_pipe_handle(ph_data);
1169 return (USB_SUCCESS);
1174 * usb_pipe_set_private:
1175 * set private client date in the pipe handle
1178 usb_pipe_set_private(usb_pipe_handle_t pipe_handle, usb_opaque_t data)
1180 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1182 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1183 "usb_pipe_set_private: ");
1185 if (ph_data == NULL) {
1187 return (USB_INVALID_PIPE);
1189 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1190 usba_release_ph_data(ph_data->p_ph_impl);
1192 return (USB_INVALID_PERM);
1195 mutex_enter(&ph_data->p_mutex);
1196 ph_data->p_client_private = data;
1197 mutex_exit(&ph_data->p_mutex);
1199 usba_release_ph_data(ph_data->p_ph_impl);
1201 return (USB_SUCCESS);
1206 * usb_pipe_get_private:
1207 * get private client date from the pipe handle
1209 usb_opaque_t
1210 usb_pipe_get_private(usb_pipe_handle_t pipe_handle)
1212 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1213 usb_opaque_t data;
1215 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1216 "usb_pipe_get_private:");
1218 if (ph_data == NULL) {
1220 return (NULL);
1223 mutex_enter(&ph_data->p_mutex);
1224 data = ph_data->p_client_private;
1225 mutex_exit(&ph_data->p_mutex);
1227 usba_release_ph_data(ph_data->p_ph_impl);
1229 return (data);
1234 * usb_pipe_reset
1235 * Arguments:
1236 * dip - devinfo pointer
1237 * pipe_handle - opaque pipe handle
1238 * Returns:
1239 * USB_SUCCESS - pipe successfully reset or request queued
1240 * USB_FAILURE - undetermined failure
1241 * USB_INVALID_PIPE - pipe is invalid or already closed
1243 void
1244 usb_pipe_reset(dev_info_t *dip,
1245 usb_pipe_handle_t pipe_handle,
1246 usb_flags_t usb_flags,
1247 void (*callback)(
1248 usb_pipe_handle_t ph,
1249 usb_opaque_t arg,
1250 int rval,
1251 usb_cb_flags_t flags),
1252 usb_opaque_t callback_arg)
1254 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1255 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1256 usb_cb_flags_t callback_flags;
1258 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1259 "usb_pipe_reset: dip=0x%p ph=0x%p uf=0x%x",
1260 (void *)dip, (void *)pipe_handle, usb_flags);
1262 callback_flags = usba_check_intr_context(USB_CB_NO_INFO);
1264 if ((dip == NULL) || (ph_data == NULL)) {
1265 if (callback) {
1266 callback(pipe_handle, callback_arg,
1267 USB_INVALID_ARGS, callback_flags);
1268 } else {
1269 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1270 usbai_log_handle,
1271 "usb_pipe_reset: invalid arguments");
1274 usba_release_ph_data(ph_impl);
1276 return;
1278 if (servicing_interrupt() && (usb_flags & USB_FLAGS_SLEEP)) {
1279 if (callback) {
1280 callback(pipe_handle, callback_arg,
1281 USB_INVALID_CONTEXT, callback_flags);
1282 } else {
1283 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1284 usbai_log_handle,
1285 "usb_pipe_reset: invalid context");
1288 usba_release_ph_data(ph_impl);
1290 return;
1293 mutex_enter(&ph_data->p_mutex);
1295 /* is this the default pipe? */
1296 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1297 if ((usb_flags & USBA_FLAGS_PRIVILEGED) == 0) {
1298 USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
1299 "usb_pipe_reset: not allowed to reset def pipe");
1300 mutex_exit(&ph_data->p_mutex);
1302 if (callback) {
1303 callback(pipe_handle, callback_arg,
1304 USB_INVALID_PIPE, callback_flags);
1305 } else {
1306 USB_DPRINTF_L2(DPRINT_MASK_USBAI,
1307 usbai_log_handle,
1308 "usb_pipe_reset: invalid pipe");
1310 usba_release_ph_data(ph_impl);
1312 return;
1315 mutex_exit(&ph_data->p_mutex);
1317 (void) usba_pipe_setup_func_call(dip,
1318 usba_pipe_sync_reset, ph_impl, NULL, usb_flags, callback,
1319 callback_arg);
1323 /*ARGSUSED*/
1325 usba_pipe_sync_reset(dev_info_t *dip,
1326 usba_ph_impl_t *ph_impl,
1327 usba_pipe_async_req_t *request,
1328 usb_flags_t usb_flags)
1330 int rval, draining_succeeded;
1331 usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1332 ph_impl);
1333 usba_device_t *usba_device;
1335 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1336 "usba_pipe_sync_reset: dip=0x%p ph_data=0x%p uf=0x%x",
1337 (void *)dip, (void *)ph_data, usb_flags);
1339 mutex_enter(&ph_data->p_mutex);
1340 usba_device = ph_data->p_usba_device;
1341 mutex_exit(&ph_data->p_mutex);
1343 rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1344 usb_flags);
1345 mutex_enter(&ph_data->p_mutex);
1348 * The host controller has stopped polling of the endpoint.
1350 draining_succeeded = usba_drain_cbs(ph_data, USB_CB_RESET_PIPE,
1351 USB_CR_PIPE_RESET);
1353 /* this MUST have succeeded */
1354 ASSERT(draining_succeeded == USB_SUCCESS);
1356 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1357 mutex_exit(&ph_data->p_mutex);
1360 * if there are requests still queued on the default pipe,
1361 * start them now
1363 usba_start_next_req(ph_data);
1365 usba_release_ph_data(ph_impl);
1367 return (rval);
1372 * usba_pipe_clear:
1373 * call hcd to clear pipe but don't wait for draining
1375 void
1376 usba_pipe_clear(usb_pipe_handle_t pipe_handle)
1378 usba_pipe_handle_data_t *ph_data = usba_get_ph_data(pipe_handle);
1379 usba_device_t *usba_device;
1380 usba_req_wrapper_t *req_wrp;
1381 int flush_requests = 1;
1383 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1384 "usba_pipe_clear: ph_data=0x%p", (void *)ph_data);
1386 if (ph_data == NULL) {
1388 return;
1391 mutex_enter(&ph_data->p_mutex);
1392 if (USBA_PIPE_CLOSING(usba_get_ph_state(ph_data))) {
1393 mutex_exit(&ph_data->p_mutex);
1395 return;
1397 usba_device = ph_data->p_usba_device;
1398 mutex_exit(&ph_data->p_mutex);
1400 (void) usba_device->usb_hcdi_ops->usba_hcdi_pipe_reset(ph_data,
1401 USB_FLAGS_SLEEP);
1403 mutex_enter(&ph_data->p_mutex);
1404 if (ph_data->p_dip) {
1405 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1406 USB_DPRINTF_L4(DPRINT_MASK_USBAI,
1407 usbai_log_handle,
1408 "no flushing on default pipe!");
1410 flush_requests = 0;
1414 if (flush_requests) {
1415 /* flush all requests in the pipehandle queue */
1416 while ((req_wrp = (usba_req_wrapper_t *)
1417 usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
1418 mutex_exit(&ph_data->p_mutex);
1419 usba_do_req_exc_cb(req_wrp, USB_CR_FLUSHED,
1420 USB_CB_RESET_PIPE);
1421 mutex_enter(&ph_data->p_mutex);
1425 usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
1426 mutex_exit(&ph_data->p_mutex);
1432 * usb_pipe_drain_reqs
1433 * this function blocks until there are no more requests
1434 * owned by this dip on the pipe
1436 * Arguments:
1437 * dip - devinfo pointer
1438 * pipe_handle - opaque pipe handle
1439 * timeout - timeout in seconds
1440 * flags - USB_FLAGS_SLEEP:
1441 * wait for completion.
1442 * cb - if USB_FLAGS_SLEEP has not been specified
1443 * this callback function will be called on
1444 * completion. This callback may be NULL
1445 * and no notification of completion will then
1446 * be provided.
1447 * cb_arg - 2nd argument to callback function.
1449 * callback and callback_arg should be NULL if USB_FLAGS_SLEEP has
1450 * been specified
1452 * Returns:
1453 * USB_SUCCESS - pipe successfully reset or request queued
1454 * USB_FAILURE - timeout
1455 * USB_* - refer to usbai.h
1458 usb_pipe_drain_reqs(dev_info_t *dip,
1459 usb_pipe_handle_t pipe_handle,
1460 uint_t time,
1461 usb_flags_t usb_flags,
1462 void (*cb)(
1463 usb_pipe_handle_t ph,
1464 usb_opaque_t arg, /* cb arg */
1465 int rval,
1466 usb_cb_flags_t flags),
1467 usb_opaque_t cb_arg)
1469 usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
1470 usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
1472 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1473 "usb_pipe_drain_reqs: dip=0x%p ph_data=0x%p tm=%d uf=0x%x",
1474 (void *)dip, (void *)ph_data, time, usb_flags);
1476 if (ph_data == NULL) {
1478 return (USB_INVALID_PIPE);
1480 if (dip == NULL) {
1481 usba_release_ph_data(ph_impl);
1483 return (USB_INVALID_ARGS);
1486 if ((usb_flags & USB_FLAGS_SLEEP) && servicing_interrupt()) {
1487 usba_release_ph_data(ph_impl);
1489 return (USB_INVALID_CONTEXT);
1492 (void) usba_pipe_setup_func_call(dip, usba_pipe_sync_drain_reqs,
1493 ph_impl, (usb_opaque_t)((uintptr_t)time), usb_flags, cb, cb_arg);
1495 return (USB_SUCCESS);
1500 * usba_pipe_sync_drain_reqs
1501 * this function blocks until there are no more requests
1502 * owned by this dip on the pipe
1504 * Arguments:
1505 * dip - devinfo pointer
1506 * ph_impl - pipe impl handle
1507 * timeout - timeout in seconds
1508 * Returns:
1509 * USB_SUCCESS - pipe successfully reset or request queued
1510 * USB_FAILURE - timeout
1511 * USB_* - see usbai.h
1513 /*ARGSUSED*/
1515 usba_pipe_sync_drain_reqs(dev_info_t *dip,
1516 usba_ph_impl_t *ph_impl,
1517 usba_pipe_async_req_t *request,
1518 usb_flags_t usb_flags)
1520 usba_pipe_handle_data_t *ph_data = usba_get_ph_data((usb_pipe_handle_t)
1521 ph_impl);
1522 int i;
1523 int timeout = 100 * (int)((uintptr_t)(request->arg));
1524 /* delay will be 10 ms */
1526 mutex_enter(&ph_data->p_mutex);
1528 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1529 "usba_pipe_sync_drain_reqs: "
1530 "dip=0x%p ph_data=0x%p timeout=%d ref=%d req=%d",
1531 (void *)dip, (void *)ph_data, timeout,
1532 usba_get_ph_ref_count(ph_data),
1533 ph_data->p_req_count);
1535 ASSERT(ph_data->p_req_count >= 0);
1538 * for default pipe, we need to check the active request
1539 * and the queue
1540 * Note that a pipe reset on the default pipe doesn't flush
1541 * the queue
1542 * for all other pipes we just check ref and req count since
1543 * these pipes are unshared
1545 if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1546 for (i = 0; (i < timeout) || (request->arg == 0); i++) {
1547 usba_list_entry_t *next, *tmpnext;
1548 usba_req_wrapper_t *req_wrp = (usba_req_wrapper_t *)
1549 ph_data->p_active_cntrl_req_wrp;
1550 int found = 0;
1551 int count = 0;
1553 /* active_req_wrp is only for control pipes */
1554 if ((req_wrp == NULL) || (req_wrp->wr_dip != dip)) {
1555 /* walk the queue */
1556 mutex_enter(&ph_data->p_queue.list_mutex);
1557 next = ph_data->p_queue.next;
1558 while (next != NULL) {
1559 mutex_enter(&next->list_mutex);
1560 req_wrp = (usba_req_wrapper_t *)
1561 next->private;
1562 found = (req_wrp->wr_dip == dip);
1563 if (found) {
1564 mutex_exit(&next->list_mutex);
1566 break;
1568 tmpnext = next->next;
1569 mutex_exit(&next->list_mutex);
1570 next = tmpnext;
1571 count++;
1573 mutex_exit(&ph_data->p_queue.list_mutex);
1574 if (found == 0) {
1575 break;
1579 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1580 "usb_pipe_sync_drain_reqs: "
1581 "cnt=%d active_req_wrp=0x%p",
1582 count, (void *)ph_data->p_active_cntrl_req_wrp);
1584 mutex_exit(&ph_data->p_mutex);
1585 delay(drv_usectohz(10000));
1586 mutex_enter(&ph_data->p_mutex);
1588 } else {
1589 mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
1590 for (i = 0; (i < timeout) || (request->arg == 0); i++) {
1591 ASSERT(ph_data->p_req_count >= 0);
1592 if (ph_data->p_req_count ||
1593 (ph_data->p_ph_impl->usba_ph_ref_count > 1)) {
1594 mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
1595 mutex_exit(&ph_data->p_mutex);
1596 delay(drv_usectohz(10000));
1597 mutex_enter(&ph_data->p_mutex);
1598 mutex_enter(&ph_data->p_ph_impl->usba_ph_mutex);
1599 } else {
1600 break;
1603 mutex_exit(&ph_data->p_ph_impl->usba_ph_mutex);
1606 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1607 "usb_pipe_sync_drain_reqs: timeout=%d active_req_wrp=0x%p req=%d",
1608 i, (void *)ph_data->p_active_cntrl_req_wrp, ph_data->p_req_count);
1610 mutex_exit(&ph_data->p_mutex);
1612 usba_release_ph_data(ph_impl);
1614 return (i >= timeout ? USB_FAILURE : USB_SUCCESS);
1619 * usba_persistent_pipe_open
1620 * Open all the pipes marked persistent for this device
1623 usba_persistent_pipe_open(usba_device_t *usba_device)
1625 usba_ph_impl_t *ph_impl;
1626 usb_pipe_handle_t pipe_handle;
1627 int i;
1628 int rval = USB_SUCCESS;
1630 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1631 "usba_persistent_pipe_open: usba_device=0x%p", (void *)usba_device);
1633 if (usba_device != NULL) {
1634 /* default pipe is the first one to be opened */
1635 mutex_enter(&usba_device->usb_mutex);
1636 for (i = 0; (rval == USB_SUCCESS) &&
1637 (i < USBA_N_ENDPOINTS); i++) {
1639 ph_impl = &usba_device->usb_ph_list[i];
1640 mutex_enter(&ph_impl->usba_ph_mutex);
1641 if (ph_impl->usba_ph_flags & USBA_PH_DATA_PERSISTENT) {
1642 ph_impl->usba_ph_flags &=
1643 ~USBA_PH_DATA_PERSISTENT;
1644 mutex_exit(&ph_impl->usba_ph_mutex);
1645 mutex_exit(&usba_device->usb_mutex);
1647 rval = usb_pipe_open(ph_impl->usba_ph_dip,
1648 &ph_impl->usba_ph_ep,
1649 &ph_impl->usba_ph_policy,
1650 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
1651 &pipe_handle);
1653 USB_DPRINTF_L3(DPRINT_MASK_USBAI,
1654 usbai_log_handle,
1655 "usba_persistent_pipe_open: "
1656 "ep_index=%d, rval=%d", i, rval);
1657 mutex_enter(&usba_device->usb_mutex);
1658 mutex_enter(&ph_impl->usba_ph_mutex);
1660 mutex_exit(&ph_impl->usba_ph_mutex);
1662 mutex_exit(&usba_device->usb_mutex);
1665 return (rval);
1670 * usba_persistent_pipe_close
1671 * Close all pipes of this device and mark them persistent
1673 void
1674 usba_persistent_pipe_close(usba_device_t *usba_device)
1676 usba_ph_impl_t *ph_impl;
1677 usb_pipe_handle_t pipe_handle;
1678 int i;
1680 USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1681 "usba_persistent_pipe_close: usba_device=0x%p",
1682 (void *)usba_device);
1684 if (usba_device != NULL) {
1685 /* default pipe is the last one to be closed */
1686 mutex_enter(&usba_device->usb_mutex);
1688 for (i = (USBA_N_ENDPOINTS - 1); i >= 0; i--) {
1689 ph_impl = &usba_device->usb_ph_list[i];
1690 if (ph_impl->usba_ph_data != NULL) {
1691 mutex_enter(&ph_impl->usba_ph_mutex);
1692 ph_impl->usba_ph_flags |=
1693 USBA_PH_DATA_PERSISTENT;
1694 mutex_exit(&ph_impl->usba_ph_mutex);
1695 mutex_exit(&usba_device->usb_mutex);
1697 pipe_handle = (usb_pipe_handle_t)ph_impl;
1699 usb_pipe_close(ph_impl->usba_ph_dip,
1700 pipe_handle,
1701 USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
1702 NULL, NULL);
1703 mutex_enter(&usba_device->usb_mutex);
1704 ASSERT(ph_impl->usba_ph_data == NULL);
1707 mutex_exit(&usba_device->usb_mutex);