10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52495Sgc161489 * Common Development and Distribution License (the "License").
62495Sgc161489 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
225773Sqz150045 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * USBA: Solaris USB Architecture support
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * functions that deal with allocation/free/data_xfers
310Sstevel@tonic-gate * for the control/bulk/interrupt/isoch pipes:
320Sstevel@tonic-gate * usb_alloc_ctrl_req()
330Sstevel@tonic-gate * usb_free_ctrl_req()
340Sstevel@tonic-gate * usb_pipe_ctrl_xfer()
350Sstevel@tonic-gate * usb_pipe_sync_ctrl_xfer()
360Sstevel@tonic-gate * usb_pipe_ctrl_xfer_wait()
370Sstevel@tonic-gate *
380Sstevel@tonic-gate * usb_alloc_bulk_req()
390Sstevel@tonic-gate * usb_free_bulk_req()
400Sstevel@tonic-gate * usb_pipe_bulk_xfer()
410Sstevel@tonic-gate * usb_pipe_bulk_transfer_size()
420Sstevel@tonic-gate *
430Sstevel@tonic-gate * usb_alloc_intr_req()
440Sstevel@tonic-gate * usb_free_intr_req()
450Sstevel@tonic-gate * usb_pipe_intr_xfer()
460Sstevel@tonic-gate * usb_pipe_stop_intr_polling()
470Sstevel@tonic-gate *
480Sstevel@tonic-gate * usb_alloc_isoc_req()
490Sstevel@tonic-gate * usb_free_isoc_req()
500Sstevel@tonic-gate * usb_get_current_frame_number()
510Sstevel@tonic-gate * usb_get_max_isoc_pkts()
520Sstevel@tonic-gate * usb_pipe_isoc_xfer()
530Sstevel@tonic-gate * usb_pipe_stop_isoc_polling()
540Sstevel@tonic-gate *
550Sstevel@tonic-gate * XXX to do:
560Sstevel@tonic-gate * update return values where needed
570Sstevel@tonic-gate * keep track of requests not freed
580Sstevel@tonic-gate *
590Sstevel@tonic-gate */
600Sstevel@tonic-gate #define USBA_FRAMEWORK
610Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
620Sstevel@tonic-gate #include <sys/usb/usba/hcdi_impl.h>
630Sstevel@tonic-gate #include <sys/strsubr.h>
64*7492SZhigang.Lu@Sun.COM #include <sys/strsun.h>
650Sstevel@tonic-gate
660Sstevel@tonic-gate /* prototypes */
670Sstevel@tonic-gate static int usba_flags_attr_check(usba_pipe_handle_data_t *,
680Sstevel@tonic-gate usb_req_attrs_t attrs, usb_flags_t);
690Sstevel@tonic-gate static int _usba_check_req(usba_pipe_handle_data_t *, usb_opaque_t,
700Sstevel@tonic-gate usb_flags_t, uchar_t);
710Sstevel@tonic-gate
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * usba_check_req:
740Sstevel@tonic-gate * check pipe, request structure for validity
750Sstevel@tonic-gate *
760Sstevel@tonic-gate * Arguments:
770Sstevel@tonic-gate * ph - pipe handle pointer
780Sstevel@tonic-gate * req - opaque request pointer
790Sstevel@tonic-gate * flags - usb flags
800Sstevel@tonic-gate *
810Sstevel@tonic-gate * Returns:
820Sstevel@tonic-gate * USB_SUCCESS - valid request
830Sstevel@tonic-gate * USB_INVALID_REQUEST - request contains some invalid values
840Sstevel@tonic-gate * USB_PIPE_ERROR - pipe is in error state
850Sstevel@tonic-gate * USB_INVALID_CONTEXT - sleep in interrupt context
860Sstevel@tonic-gate * USB_INVALID_PIPE - zero pipe or wrong pipe
870Sstevel@tonic-gate */
880Sstevel@tonic-gate static int
usba_check_req(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_flags_t flags,uchar_t pipe_type)890Sstevel@tonic-gate usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
900Sstevel@tonic-gate usb_flags_t flags, uchar_t pipe_type)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate int rval = _usba_check_req(ph_data, req, flags, pipe_type);
930Sstevel@tonic-gate
940Sstevel@tonic-gate if (rval != USB_SUCCESS) {
950Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
960Sstevel@tonic-gate "usba_check_req: ph_data=0x%p req=0x%p flags=0%x rval=%d",
976898Sfb209375 (void *)ph_data, (void *)req, flags, rval);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate
1000Sstevel@tonic-gate return (rval);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate static int
_usba_check_req(usba_pipe_handle_data_t * ph_data,usb_opaque_t req,usb_flags_t flags,uchar_t pipe_type)1050Sstevel@tonic-gate _usba_check_req(usba_pipe_handle_data_t *ph_data, usb_opaque_t req,
1060Sstevel@tonic-gate usb_flags_t flags, uchar_t pipe_type)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)req;
1090Sstevel@tonic-gate usb_bulk_req_t *bulk_req = (usb_bulk_req_t *)req;
1100Sstevel@tonic-gate usb_intr_req_t *intr_req = (usb_intr_req_t *)req;
1110Sstevel@tonic-gate usb_isoc_req_t *isoc_req = (usb_isoc_req_t *)req;
1120Sstevel@tonic-gate usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
1130Sstevel@tonic-gate mblk_t *data;
1140Sstevel@tonic-gate usb_cr_t *cr;
1150Sstevel@tonic-gate usb_req_attrs_t attrs;
1160Sstevel@tonic-gate usb_opaque_t cb, exc_cb;
1170Sstevel@tonic-gate uint_t timeout = 0;
1180Sstevel@tonic-gate uchar_t direction = ph_data->p_ep.bEndpointAddress &
1195773Sqz150045 USB_EP_DIR_MASK;
1200Sstevel@tonic-gate uchar_t ep_attrs = ph_data->p_ep.bmAttributes &
1215773Sqz150045 USB_EP_ATTR_MASK;
1220Sstevel@tonic-gate int n;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
1250Sstevel@tonic-gate "usba_check_req: ph_data=0x%p req=0x%p flags=0x%x",
1266898Sfb209375 (void *)ph_data, (void *)req, flags);
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate if (req == NULL) {
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate return (USB_INVALID_ARGS);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate /* set completion reason first so it specifies an error */
1340Sstevel@tonic-gate switch (ep_attrs) {
1350Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
1360Sstevel@tonic-gate cr = &ctrl_req->ctrl_completion_reason;
1370Sstevel@tonic-gate break;
1380Sstevel@tonic-gate case USB_EP_ATTR_BULK:
1390Sstevel@tonic-gate cr = &bulk_req->bulk_completion_reason;
1400Sstevel@tonic-gate break;
1410Sstevel@tonic-gate case USB_EP_ATTR_INTR:
1420Sstevel@tonic-gate cr = &intr_req->intr_completion_reason;
1430Sstevel@tonic-gate break;
1440Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
1450Sstevel@tonic-gate cr = &isoc_req->isoc_completion_reason;
1460Sstevel@tonic-gate break;
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate *cr = USB_CR_UNSPECIFIED_ERR;
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate return (USB_INVALID_CONTEXT);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate if (pipe_type != ep_attrs) {
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate return (USB_INVALID_PIPE);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate /* we must have usba_device and default ph to do autoclearing */
1620Sstevel@tonic-gate ASSERT(ph_data->p_usba_device);
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate if (ph_data->p_usba_device->usb_ph_list[0].usba_ph_data == NULL) {
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate return (USB_INVALID_PIPE);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /* check if this is a valid request packet, ie. not freed */
1700Sstevel@tonic-gate if (usba_check_in_list(&(ph_data->p_usba_device->usb_allocated),
1710Sstevel@tonic-gate &wrp->wr_allocated_list) != USB_SUCCESS) {
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate return (USB_INVALID_REQUEST);
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /* copy over some members for easy checking later */
1770Sstevel@tonic-gate switch (ep_attrs) {
1780Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
1790Sstevel@tonic-gate ctrl_req->ctrl_cb_flags = USB_CB_NO_INFO;
1800Sstevel@tonic-gate data = ctrl_req->ctrl_data;
1810Sstevel@tonic-gate attrs = ctrl_req->ctrl_attributes;
1820Sstevel@tonic-gate timeout = ctrl_req->ctrl_timeout;
1830Sstevel@tonic-gate cb = (usb_opaque_t)ctrl_req->ctrl_cb;
1840Sstevel@tonic-gate exc_cb = (usb_opaque_t)ctrl_req->ctrl_exc_cb;
1850Sstevel@tonic-gate if (flags & USB_FLAGS_SLEEP) {
1860Sstevel@tonic-gate flags |= USBA_WRP_FLAGS_WAIT;
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate /* force auto clearing on the default pipe */
1890Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) {
1900Sstevel@tonic-gate attrs |= USB_ATTRS_AUTOCLEARING;
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate break;
1930Sstevel@tonic-gate case USB_EP_ATTR_BULK:
1940Sstevel@tonic-gate bulk_req->bulk_cb_flags = USB_CB_NO_INFO;
1950Sstevel@tonic-gate data = bulk_req->bulk_data;
1960Sstevel@tonic-gate attrs = bulk_req->bulk_attributes;
1970Sstevel@tonic-gate timeout = bulk_req->bulk_timeout;
1980Sstevel@tonic-gate cb = (usb_opaque_t)bulk_req->bulk_cb;
1990Sstevel@tonic-gate exc_cb = (usb_opaque_t)bulk_req->bulk_exc_cb;
2000Sstevel@tonic-gate if (flags & USB_FLAGS_SLEEP) {
2010Sstevel@tonic-gate flags |= USBA_WRP_FLAGS_WAIT;
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate break;
2040Sstevel@tonic-gate case USB_EP_ATTR_INTR:
2050Sstevel@tonic-gate intr_req->intr_cb_flags = USB_CB_NO_INFO;
2060Sstevel@tonic-gate data = intr_req->intr_data;
2070Sstevel@tonic-gate attrs = intr_req->intr_attributes;
2080Sstevel@tonic-gate timeout = intr_req->intr_timeout;
2090Sstevel@tonic-gate cb = (usb_opaque_t)intr_req->intr_cb;
2100Sstevel@tonic-gate exc_cb = (usb_opaque_t)intr_req->intr_exc_cb;
2110Sstevel@tonic-gate if ((flags & USB_FLAGS_SLEEP) &&
2120Sstevel@tonic-gate (attrs & USB_ATTRS_ONE_XFER)) {
2130Sstevel@tonic-gate flags |= USBA_WRP_FLAGS_WAIT;
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate break;
2160Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
2170Sstevel@tonic-gate isoc_req->isoc_cb_flags = USB_CB_NO_INFO;
2180Sstevel@tonic-gate data = isoc_req->isoc_data;
2190Sstevel@tonic-gate attrs = isoc_req->isoc_attributes;
2200Sstevel@tonic-gate cb = (usb_opaque_t)isoc_req->isoc_cb;
2210Sstevel@tonic-gate exc_cb = (usb_opaque_t)isoc_req->isoc_exc_cb;
2220Sstevel@tonic-gate break;
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
2260Sstevel@tonic-gate "usba_check_req: attrs = 0x%x flags=0x%x", attrs, flags);
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /* check flags and attr combinations */
2290Sstevel@tonic-gate if (usba_flags_attr_check(ph_data, attrs, flags) !=
2300Sstevel@tonic-gate USB_SUCCESS) {
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate /* if no sleep, there must be callback ptrs */
2360Sstevel@tonic-gate if ((flags & USB_FLAGS_SLEEP) == 0) {
2370Sstevel@tonic-gate if (cb == NULL || exc_cb == NULL) {
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate switch (ep_attrs) {
2440Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
2450Sstevel@tonic-gate if (ctrl_req->ctrl_wLength && (data == NULL)) {
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate break;
2500Sstevel@tonic-gate case USB_EP_ATTR_BULK:
2512495Sgc161489 if ((bulk_req->bulk_len) && (data == NULL)) {
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate break;
2560Sstevel@tonic-gate case USB_EP_ATTR_INTR:
2570Sstevel@tonic-gate if (direction == USB_EP_DIR_OUT) {
2582495Sgc161489 if (intr_req->intr_len && data == NULL) {
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if (direction == USB_EP_DIR_IN) {
2650Sstevel@tonic-gate if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER)) {
2660Sstevel@tonic-gate if (cb == NULL || exc_cb == NULL) {
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate if (data != NULL) {
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate if (!(intr_req->intr_attributes & USB_ATTRS_ONE_XFER) &&
2760Sstevel@tonic-gate (timeout > 0)) {
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate break;
2820Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
2830Sstevel@tonic-gate if (direction == USB_EP_DIR_IN) {
2840Sstevel@tonic-gate if (cb == NULL || exc_cb == NULL) {
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
2902735Sgc161489 if (data == NULL) {
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate return (USB_INVALID_REQUEST);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate
2952735Sgc161489 /*
2962735Sgc161489 * Since ehci/ohci/uhci use (data->b_wptr - data->b_rptr) as
2972735Sgc161489 * real isoc_pkts_length, it should be checked.
2982735Sgc161489 */
2992735Sgc161489 if (direction == USB_EP_DIR_OUT) {
300*7492SZhigang.Lu@Sun.COM if (MBLKL(data) <= 0) {
3012735Sgc161489
3022735Sgc161489 return (USB_INVALID_REQUEST);
3032735Sgc161489 }
3042735Sgc161489 }
3052735Sgc161489
3060Sstevel@tonic-gate /* special isoc checks */
3070Sstevel@tonic-gate if ((isoc_req->isoc_pkts_count == 0) ||
3080Sstevel@tonic-gate (isoc_req->isoc_pkt_descr == NULL)) {
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate return (USB_INVALID_REQUEST);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate /* check attributes for conflicts, one must be specified */
3140Sstevel@tonic-gate if (!((isoc_req->isoc_attributes &
3150Sstevel@tonic-gate USB_ATTRS_ISOC_START_FRAME) ||
3160Sstevel@tonic-gate (isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP))) {
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate return (USB_NO_FRAME_NUMBER);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate /* both may not be specified */
3220Sstevel@tonic-gate if ((isoc_req->isoc_attributes &
3230Sstevel@tonic-gate (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) ==
3240Sstevel@tonic-gate (USB_ATTRS_ISOC_START_FRAME | USB_ATTRS_ISOC_XFER_ASAP)) {
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate return (USB_NO_FRAME_NUMBER);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate /* no start frame may be specified for ASAP attribute */
3300Sstevel@tonic-gate if (((isoc_req->isoc_attributes & USB_ATTRS_ISOC_XFER_ASAP)) &&
3310Sstevel@tonic-gate isoc_req->isoc_frame_no) {
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate return (USB_INVALID_REQUEST);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /* start frame must be specified for START FRAME attribute */
3370Sstevel@tonic-gate if (((isoc_req->isoc_attributes &
3380Sstevel@tonic-gate USB_ATTRS_ISOC_START_FRAME)) &&
3390Sstevel@tonic-gate (isoc_req->isoc_frame_no == 0)) {
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate return (USB_NO_FRAME_NUMBER);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate /* each packet must have initialized pkt length */
3450Sstevel@tonic-gate for (n = 0; n < isoc_req->isoc_pkts_count; n++) {
3460Sstevel@tonic-gate if (isoc_req->isoc_pkt_descr[n].isoc_pkt_length == 0) {
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate return (USB_INVALID_REQUEST);
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate break;
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /* save pipe_handle/attrs/timeout/usb_flags */
3550Sstevel@tonic-gate wrp->wr_ph_data = ph_data;
3560Sstevel@tonic-gate wrp->wr_usb_flags = flags;
3570Sstevel@tonic-gate wrp->wr_attrs = attrs;
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /* zero some fields in case the request is reused */
3600Sstevel@tonic-gate wrp->wr_done = B_FALSE;
3610Sstevel@tonic-gate wrp->wr_cr = USB_CR_OK;
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate /* this request looks good */
3640Sstevel@tonic-gate *cr = USB_CR_OK;
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate return (USB_SUCCESS);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate /*
3710Sstevel@tonic-gate * Table of invalid flags and attributes values. See "usbai.h"
3720Sstevel@tonic-gate * for a complete table on valid usb_req_attrs_t
3730Sstevel@tonic-gate */
3740Sstevel@tonic-gate #define X ((uint_t)(-1))
3750Sstevel@tonic-gate #define OUT USB_EP_DIR_OUT
3760Sstevel@tonic-gate #define IN USB_EP_DIR_IN
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate struct flags_attr {
3790Sstevel@tonic-gate uint_t ep_dir;
3800Sstevel@tonic-gate uint_t ep_attr;
3810Sstevel@tonic-gate uint_t usb_flags; /* usb_flags SLEEP or none */
3820Sstevel@tonic-gate uint_t attrs;
3830Sstevel@tonic-gate } usb_invalid_flags_attrs[] = {
3840Sstevel@tonic-gate { OUT, USB_EP_ATTR_BULK, X, USB_ATTRS_SHORT_XFER_OK },
3850Sstevel@tonic-gate { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_SHORT_XFER_OK },
3860Sstevel@tonic-gate { OUT, USB_EP_ATTR_ISOCH, X, USB_ATTRS_SHORT_XFER_OK },
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_START_FRAME },
3890Sstevel@tonic-gate { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_START_FRAME },
3900Sstevel@tonic-gate { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_START_FRAME },
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_XFER_ASAP },
3930Sstevel@tonic-gate { X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_XFER_ASAP },
3940Sstevel@tonic-gate { OUT, USB_EP_ATTR_INTR, X, USB_ATTRS_ONE_XFER },
3950Sstevel@tonic-gate { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_XFER_ASAP },
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate { X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ONE_XFER },
3980Sstevel@tonic-gate { X, USB_EP_ATTR_BULK, X, USB_ATTRS_ONE_XFER },
3990Sstevel@tonic-gate { X, USB_EP_ATTR_ISOCH, X, USB_ATTRS_ONE_XFER },
4000Sstevel@tonic-gate };
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate #define N_INVALID_FLAGS_ATTRS (sizeof (usb_invalid_flags_attrs))/ \
4030Sstevel@tonic-gate sizeof (struct flags_attr)
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate * function to check flags and attribute combinations for a particular pipe
4070Sstevel@tonic-gate * Arguments:
4080Sstevel@tonic-gate * ph - pipe handle pointer
4090Sstevel@tonic-gate * attrs - attributes of the request
4100Sstevel@tonic-gate * flags - usb_flags
4110Sstevel@tonic-gate */
4120Sstevel@tonic-gate static int
usba_flags_attr_check(usba_pipe_handle_data_t * ph_data,usb_req_attrs_t attrs,usb_flags_t flags)4130Sstevel@tonic-gate usba_flags_attr_check(usba_pipe_handle_data_t *ph_data,
4140Sstevel@tonic-gate usb_req_attrs_t attrs,
4150Sstevel@tonic-gate usb_flags_t flags)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate uchar_t i;
4180Sstevel@tonic-gate uchar_t ep_dir = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
4190Sstevel@tonic-gate uchar_t ep_attr = ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK;
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate flags &= USB_FLAGS_SLEEP; /* ignore other flags */
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /*
4240Sstevel@tonic-gate * Do some attributes validation checks here.
4250Sstevel@tonic-gate */
4260Sstevel@tonic-gate for (i = 0; i < N_INVALID_FLAGS_ATTRS; i++) {
4270Sstevel@tonic-gate if (((ep_dir == usb_invalid_flags_attrs[i].ep_dir) ||
4285773Sqz150045 (usb_invalid_flags_attrs[i].ep_dir == X)) &&
4290Sstevel@tonic-gate ((ep_attr == usb_invalid_flags_attrs[i].ep_attr) ||
4305773Sqz150045 (usb_invalid_flags_attrs[i].ep_attr == X)) &&
4310Sstevel@tonic-gate ((flags & usb_invalid_flags_attrs[i].usb_flags) ||
4325773Sqz150045 (usb_invalid_flags_attrs[i].usb_flags == X)) &&
4330Sstevel@tonic-gate ((attrs & usb_invalid_flags_attrs[i].attrs) ||
4345773Sqz150045 (usb_invalid_flags_attrs[i].attrs == X))) {
4350Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
4360Sstevel@tonic-gate "invalid (%d) : flags = 0x%x, attrs = 0x%x",
4370Sstevel@tonic-gate i, flags, attrs);
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate return (USB_INVALID_REQUEST);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate return (USB_SUCCESS);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate * usba_rval2cr:
4490Sstevel@tonic-gate * convert rval to meaningful completion reason
4500Sstevel@tonic-gate * XXX extend completion reasons to get better mapping
4510Sstevel@tonic-gate */
4520Sstevel@tonic-gate static struct {
4530Sstevel@tonic-gate int rval;
4540Sstevel@tonic-gate usb_cr_t cr;
4550Sstevel@tonic-gate } rval2cr[] = {
4560Sstevel@tonic-gate {USB_SUCCESS, USB_CR_OK},
4570Sstevel@tonic-gate {USB_FAILURE, USB_CR_UNSPECIFIED_ERR},
4580Sstevel@tonic-gate {USB_NO_RESOURCES, USB_CR_NO_RESOURCES},
4590Sstevel@tonic-gate {USB_NO_BANDWIDTH, USB_CR_NO_RESOURCES},
4600Sstevel@tonic-gate {USB_NOT_SUPPORTED, USB_CR_UNSPECIFIED_ERR},
4610Sstevel@tonic-gate {USB_PIPE_ERROR, USB_CR_UNSPECIFIED_ERR},
4620Sstevel@tonic-gate {USB_INVALID_PIPE, USB_CR_UNSPECIFIED_ERR},
4630Sstevel@tonic-gate {USB_NO_FRAME_NUMBER, USB_CR_UNSPECIFIED_ERR},
4640Sstevel@tonic-gate {USB_INVALID_START_FRAME, USB_CR_UNSPECIFIED_ERR},
4650Sstevel@tonic-gate {USB_HC_HARDWARE_ERROR, USB_CR_UNSPECIFIED_ERR},
4660Sstevel@tonic-gate {USB_INVALID_REQUEST, USB_CR_UNSPECIFIED_ERR},
4670Sstevel@tonic-gate {USB_INVALID_CONTEXT, USB_CR_UNSPECIFIED_ERR},
4680Sstevel@tonic-gate {USB_INVALID_VERSION, USB_CR_UNSPECIFIED_ERR},
4690Sstevel@tonic-gate {USB_INVALID_ARGS, USB_CR_UNSPECIFIED_ERR},
4700Sstevel@tonic-gate {USB_INVALID_PERM, USB_CR_UNSPECIFIED_ERR},
4710Sstevel@tonic-gate {USB_BUSY, USB_CR_UNSPECIFIED_ERR},
4720Sstevel@tonic-gate {0xffff, 0}
4730Sstevel@tonic-gate };
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate usb_cr_t
usba_rval2cr(int rval)4760Sstevel@tonic-gate usba_rval2cr(int rval)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate int i;
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate for (i = 0; rval2cr[i].rval != 0xffff; i++) {
4810Sstevel@tonic-gate if (rval2cr[i].rval == rval) {
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate return (rval2cr[i].cr);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate return (USB_CR_UNSPECIFIED_ERR);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate /*
4920Sstevel@tonic-gate * usba_start_next_req:
4930Sstevel@tonic-gate * Arguments:
4940Sstevel@tonic-gate * ph_data - pointer to pipe handle
4950Sstevel@tonic-gate *
4960Sstevel@tonic-gate * Currently, only ctrl/bulk requests can be queued
4970Sstevel@tonic-gate */
4980Sstevel@tonic-gate void
usba_start_next_req(usba_pipe_handle_data_t * ph_data)4990Sstevel@tonic-gate usba_start_next_req(usba_pipe_handle_data_t *ph_data)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate usb_ctrl_req_t *ctrl_req;
5020Sstevel@tonic-gate usb_bulk_req_t *bulk_req;
5030Sstevel@tonic-gate usba_req_wrapper_t *wrp;
5040Sstevel@tonic-gate uchar_t ep_attrs = ph_data->p_ep.bmAttributes &
5055773Sqz150045 USB_EP_ATTR_MASK;
5060Sstevel@tonic-gate int rval;
5070Sstevel@tonic-gate usb_pipe_state_t state;
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
5100Sstevel@tonic-gate switch (ep_attrs) {
5110Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
5120Sstevel@tonic-gate case USB_EP_ATTR_BULK:
5130Sstevel@tonic-gate switch (usba_get_ph_state(ph_data)) {
5140Sstevel@tonic-gate case USB_PIPE_STATE_IDLE:
5150Sstevel@tonic-gate case USB_PIPE_STATE_CLOSING:
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate break;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate default:
5200Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate return;
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate break;
5260Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
5270Sstevel@tonic-gate case USB_EP_ATTR_INTR:
5280Sstevel@tonic-gate default:
5290Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate return;
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate while ((wrp = (usba_req_wrapper_t *)
5350Sstevel@tonic-gate usba_rm_first_pvt_from_list(&ph_data->p_queue)) != NULL) {
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate /* only submit to HCD when idle/active */
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
5406898Sfb209375 "usba_start_next_req: ph_data=0x%p state=%d",
5416898Sfb209375 (void *)ph_data, usba_get_ph_state(ph_data));
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate if (ep_attrs == USB_EP_ATTR_CONTROL) {
5440Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate if ((state = usba_get_ph_state(ph_data)) ==
5480Sstevel@tonic-gate USB_PIPE_STATE_IDLE) {
5490Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
5500Sstevel@tonic-gate
5510Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
5526898Sfb209375 "starting req = 0x%p",
5536898Sfb209375 (void *)USBA_WRP2CTRL_REQ(wrp));
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate switch (ep_attrs) {
5560Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
5570Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5580Sstevel@tonic-gate ctrl_req = USBA_WRP2CTRL_REQ(wrp);
5590Sstevel@tonic-gate /* submit to hcd */
5600Sstevel@tonic-gate rval = ph_data->p_usba_device->usb_hcdi_ops->
5610Sstevel@tonic-gate usba_hcdi_pipe_ctrl_xfer(ph_data,
5620Sstevel@tonic-gate ctrl_req, wrp->wr_usb_flags);
5630Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
5640Sstevel@tonic-gate break;
5650Sstevel@tonic-gate case USB_EP_ATTR_BULK:
5660Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5670Sstevel@tonic-gate bulk_req = USBA_WRP2BULK_REQ(wrp);
5680Sstevel@tonic-gate /* submit to hcd */
5690Sstevel@tonic-gate rval = ph_data->p_usba_device->usb_hcdi_ops->
5700Sstevel@tonic-gate usba_hcdi_pipe_bulk_xfer(ph_data,
5710Sstevel@tonic-gate bulk_req, wrp->wr_usb_flags);
5720Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
5730Sstevel@tonic-gate break;
5740Sstevel@tonic-gate default:
5750Sstevel@tonic-gate /* there shouldn't be any requests */
5760Sstevel@tonic-gate rval = USB_FAILURE;
5770Sstevel@tonic-gate break;
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate if (rval != USB_SUCCESS) {
5810Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5820Sstevel@tonic-gate usba_do_req_exc_cb(wrp,
5830Sstevel@tonic-gate usba_rval2cr(rval),
5840Sstevel@tonic-gate USB_CB_SUBMIT_FAILED);
5850Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate /* we are done */
5880Sstevel@tonic-gate break;
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate } else {
5910Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
5920Sstevel@tonic-gate switch (state) {
5930Sstevel@tonic-gate case USB_PIPE_STATE_CLOSING:
5940Sstevel@tonic-gate usba_do_req_exc_cb(wrp, USB_CR_PIPE_CLOSING, 0);
5950Sstevel@tonic-gate break;
5960Sstevel@tonic-gate case USB_PIPE_STATE_ERROR:
5970Sstevel@tonic-gate default:
5980Sstevel@tonic-gate usba_do_req_exc_cb(wrp, USB_CR_FLUSHED, 0);
5990Sstevel@tonic-gate break;
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6066898Sfb209375 "usba_start_next_req done: ph_data=0x%p state=%d", (void *)ph_data,
6070Sstevel@tonic-gate usba_get_ph_state(ph_data));
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate * usba_req_wrapper_alloc:
6150Sstevel@tonic-gate * Allocate + Initialize a usba_req_wrapper_t
6160Sstevel@tonic-gate *
6170Sstevel@tonic-gate * Arguments:
6180Sstevel@tonic-gate * dip - dev_info_t of the client driver
6190Sstevel@tonic-gate * req_len - sizeof request
6200Sstevel@tonic-gate * flags -
6210Sstevel@tonic-gate * USB_FLAGS_SLEEP - Sleep if resources are not available
6220Sstevel@tonic-gate * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
6230Sstevel@tonic-gate *
6240Sstevel@tonic-gate * Return Values:
6250Sstevel@tonic-gate * pointer to usba_req_wrapper_t on success; NULL on failure.
6260Sstevel@tonic-gate *
6270Sstevel@tonic-gate */
6280Sstevel@tonic-gate static usba_req_wrapper_t *
usba_req_wrapper_alloc(dev_info_t * dip,size_t req_len,usb_flags_t flags)6290Sstevel@tonic-gate usba_req_wrapper_alloc(dev_info_t *dip,
6300Sstevel@tonic-gate size_t req_len,
6310Sstevel@tonic-gate usb_flags_t flags)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate int kmflag;
6340Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
6350Sstevel@tonic-gate usba_req_wrapper_t *wrp;
6360Sstevel@tonic-gate size_t wr_length = sizeof (usba_req_wrapper_t) + req_len;
6370Sstevel@tonic-gate ddi_iblock_cookie_t iblock_cookie =
6385773Sqz150045 usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
6395773Sqz150045 hcdi_iblock_cookie;
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate return (NULL);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate kmflag = (flags & USB_FLAGS_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate /* Allocate the usb_{c/b/i/i}_req + usba_req_wrapper_t structure */
6490Sstevel@tonic-gate if ((wrp = kmem_zalloc(wr_length, kmflag)) != NULL) {
6500Sstevel@tonic-gate wrp->wr_length = wr_length;
6510Sstevel@tonic-gate wrp->wr_dip = dip;
6520Sstevel@tonic-gate wrp->wr_req = (usb_opaque_t)USBA_SETREQ_ADDR(wrp);
6530Sstevel@tonic-gate cv_init(&wrp->wr_cv, NULL, CV_DRIVER, NULL);
6540Sstevel@tonic-gate
6550Sstevel@tonic-gate /* initialize mutex for the queue */
6560Sstevel@tonic-gate usba_init_list(&wrp->wr_queue, (usb_opaque_t)wrp,
6575773Sqz150045 iblock_cookie);
6580Sstevel@tonic-gate usba_init_list(&wrp->wr_allocated_list, (usb_opaque_t)wrp,
6595773Sqz150045 iblock_cookie);
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate usba_add_to_list(&usba_device->usb_allocated,
6620Sstevel@tonic-gate &wrp->wr_allocated_list);
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6656898Sfb209375 "usba_req_wrapper_alloc: wrp = 0x%p", (void *)wrp);
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate return (wrp);
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate /*
6730Sstevel@tonic-gate * usba_req_wrapper_free:
6740Sstevel@tonic-gate * Frees a usba_req_wrapper_t. Get rid of lists if any.
6750Sstevel@tonic-gate *
6760Sstevel@tonic-gate * Arguments:
6770Sstevel@tonic-gate * wrp: request wrapper structure
6780Sstevel@tonic-gate */
6790Sstevel@tonic-gate void
usba_req_wrapper_free(usba_req_wrapper_t * wrp)6800Sstevel@tonic-gate usba_req_wrapper_free(usba_req_wrapper_t *wrp)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate usba_device_t *usba_device;
6830Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data;
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
6866898Sfb209375 "usba_req_wrapper_free: wrp=0x%p", (void *)wrp);
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate if (wrp) {
6890Sstevel@tonic-gate /* remove from queues */
6900Sstevel@tonic-gate ph_data = USBA_WRP2PH_DATA(wrp);
6910Sstevel@tonic-gate if (ph_data) {
6920Sstevel@tonic-gate (void) usba_rm_from_list(&ph_data->p_queue,
6935773Sqz150045 &wrp->wr_queue);
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate usba_device = usba_get_usba_device(wrp->wr_dip);
6960Sstevel@tonic-gate if (usba_rm_from_list(&usba_device->usb_allocated,
6970Sstevel@tonic-gate &wrp->wr_allocated_list) != USB_SUCCESS) {
6980Sstevel@tonic-gate cmn_err(CE_PANIC,
6990Sstevel@tonic-gate "usba_req_wrapper_free: data corruption");
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate usba_destroy_list(&wrp->wr_queue);
7020Sstevel@tonic-gate usba_destroy_list(&wrp->wr_allocated_list);
7030Sstevel@tonic-gate cv_destroy(&wrp->wr_cv);
7040Sstevel@tonic-gate kmem_free(wrp, wrp->wr_length);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate /*
7100Sstevel@tonic-gate * usba_check_intr_context
7110Sstevel@tonic-gate * Set USB_CB_INTR_CONTEXT callback flag if executing in interrupt context
7120Sstevel@tonic-gate */
7130Sstevel@tonic-gate usb_cb_flags_t
usba_check_intr_context(usb_cb_flags_t cb_flags)7140Sstevel@tonic-gate usba_check_intr_context(usb_cb_flags_t cb_flags)
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate if (servicing_interrupt() != 0) {
7170Sstevel@tonic-gate cb_flags |= USB_CB_INTR_CONTEXT;
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate return (cb_flags);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate /*
7250Sstevel@tonic-gate * usba_req_normal_cb:
7260Sstevel@tonic-gate * perform normal callback depending on request type
7270Sstevel@tonic-gate */
7280Sstevel@tonic-gate void
usba_req_normal_cb(usba_req_wrapper_t * req_wrp)7290Sstevel@tonic-gate usba_req_normal_cb(usba_req_wrapper_t *req_wrp)
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
7320Sstevel@tonic-gate usb_pipe_handle_t pipe_handle;
7330Sstevel@tonic-gate uint_t direction = ph_data->p_ep.bEndpointAddress &
7345773Sqz150045 USB_EP_DIR_MASK;
7350Sstevel@tonic-gate usb_pipe_state_t pipe_state;
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate pipe_handle = usba_get_pipe_handle(ph_data);
7380Sstevel@tonic-gate
7390Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
7400Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
7410Sstevel@tonic-gate pipe_state = usba_get_ph_state(ph_data);
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
7440Sstevel@tonic-gate "usba_req_normal_cb: "
7450Sstevel@tonic-gate "ph_data=0x%p state=%d wrp=0x%p ref=%d req=%d",
7466898Sfb209375 (void *)ph_data, pipe_state, (void *)req_wrp,
7476898Sfb209375 usba_get_ph_ref_count(ph_data), ph_data->p_req_count);
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate ASSERT((pipe_state == USB_PIPE_STATE_ACTIVE) ||
7500Sstevel@tonic-gate (pipe_state == USB_PIPE_STATE_CLOSING));
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate /* set done to indicate that we will do callback or cv_signal */
7530Sstevel@tonic-gate ASSERT(req_wrp->wr_done == B_FALSE);
7540Sstevel@tonic-gate req_wrp->wr_done = B_TRUE;
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate /* update the pipe state */
7570Sstevel@tonic-gate switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
7580Sstevel@tonic-gate USB_EP_ATTR_MASK) {
7590Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
7600Sstevel@tonic-gate case USB_EP_ATTR_BULK:
7610Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7620Sstevel@tonic-gate break;
7630Sstevel@tonic-gate case USB_EP_ATTR_INTR:
7640Sstevel@tonic-gate if ((direction == USB_EP_DIR_IN) &&
7650Sstevel@tonic-gate (USBA_WRP2INTR_REQ(req_wrp)->intr_attributes &
7660Sstevel@tonic-gate USB_ATTRS_ONE_XFER)) {
7670Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7680Sstevel@tonic-gate } else if ((direction == USB_EP_DIR_OUT) &&
7690Sstevel@tonic-gate (ph_data->p_req_count == 0)) {
7700Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate break;
7730Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
7740Sstevel@tonic-gate if ((ph_data->p_req_count == 0) &&
7750Sstevel@tonic-gate (direction == USB_EP_DIR_OUT)) {
7760Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate break;
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate /* now complete the request */
7830Sstevel@tonic-gate if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
7840Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp = NULL;
7850Sstevel@tonic-gate cv_signal(&req_wrp->wr_cv);
7860Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
7870Sstevel@tonic-gate } else {
7880Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate /* This sets USB_CB_INTR_CONTEXT as needed. */
7910Sstevel@tonic-gate usba_req_set_cb_flags(req_wrp, USB_CB_NO_INFO);
7920Sstevel@tonic-gate
7930Sstevel@tonic-gate switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
7940Sstevel@tonic-gate USB_EP_ATTR_MASK) {
7950Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
7960Sstevel@tonic-gate USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb(pipe_handle,
7975773Sqz150045 USBA_WRP2CTRL_REQ(req_wrp));
7980Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
7990Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp = NULL;
8000Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
8010Sstevel@tonic-gate break;
8020Sstevel@tonic-gate case USB_EP_ATTR_INTR:
8030Sstevel@tonic-gate USBA_WRP2INTR_REQ(req_wrp)->intr_cb(pipe_handle,
8045773Sqz150045 USBA_WRP2INTR_REQ(req_wrp));
8050Sstevel@tonic-gate break;
8060Sstevel@tonic-gate case USB_EP_ATTR_BULK:
8070Sstevel@tonic-gate USBA_WRP2BULK_REQ(req_wrp)->bulk_cb(pipe_handle,
8085773Sqz150045 USBA_WRP2BULK_REQ(req_wrp));
8090Sstevel@tonic-gate break;
8100Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
8110Sstevel@tonic-gate USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb(pipe_handle,
8125773Sqz150045 USBA_WRP2ISOC_REQ(req_wrp));
8130Sstevel@tonic-gate break;
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate }
8160Sstevel@tonic-gate
8170Sstevel@tonic-gate /* we are done with this request */
8180Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
8190Sstevel@tonic-gate ph_data->p_req_count--;
8200Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
8210Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate /*
8260Sstevel@tonic-gate * usba_req_exc_cb:
8270Sstevel@tonic-gate * perform exception cb depending on request type.
8280Sstevel@tonic-gate * ensure the completion reason is non zero
8290Sstevel@tonic-gate */
8300Sstevel@tonic-gate void
usba_req_exc_cb(usba_req_wrapper_t * req_wrp,usb_cr_t cr,usb_cb_flags_t cb_flags)8310Sstevel@tonic-gate usba_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
8320Sstevel@tonic-gate usb_cb_flags_t cb_flags)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = req_wrp->wr_ph_data;
8350Sstevel@tonic-gate usb_pipe_handle_t pipe_handle = usba_get_pipe_handle(ph_data);
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate mutex_enter(&req_wrp->wr_ph_data->p_mutex);
8380Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
8390Sstevel@tonic-gate "usba_req_exc_cb: %s%d: ph_data=0x%p (ep%x) state=%d wrp=0x%p "
8400Sstevel@tonic-gate "ref=%d reqcnt=%d cr=%d",
8410Sstevel@tonic-gate ddi_driver_name(req_wrp->wr_dip),
8420Sstevel@tonic-gate ddi_get_instance(req_wrp->wr_dip),
8436898Sfb209375 (void *)ph_data, ph_data->p_ep.bEndpointAddress,
8446898Sfb209375 usba_get_ph_state(ph_data), (void *)req_wrp,
8456898Sfb209375 usba_get_ph_ref_count(ph_data), ph_data->p_req_count,
8466898Sfb209375 req_wrp->wr_cr);
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate ASSERT(req_wrp->wr_ph_data->p_req_count >= 0);
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate usba_req_set_cb_flags(req_wrp, cb_flags);
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate /* if there was no CR set already, set it now */
8530Sstevel@tonic-gate if (req_wrp->wr_cr == USB_CR_OK) {
8540Sstevel@tonic-gate req_wrp->wr_cr = (cr != USB_CR_OK) ?
8555773Sqz150045 cr : USB_CR_UNSPECIFIED_ERR;
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate ASSERT(req_wrp->wr_done == B_FALSE);
8590Sstevel@tonic-gate req_wrp->wr_done = B_TRUE;
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
8620Sstevel@tonic-gate USB_EP_ATTR_MASK) {
8630Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
8640Sstevel@tonic-gate if (USBA_WRP2CTRL_REQ(req_wrp)->
8650Sstevel@tonic-gate ctrl_completion_reason == USB_CR_OK) {
8660Sstevel@tonic-gate USBA_WRP2CTRL_REQ(req_wrp)->
8670Sstevel@tonic-gate ctrl_completion_reason = req_wrp->wr_cr;
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate break;
8700Sstevel@tonic-gate case USB_EP_ATTR_INTR:
8710Sstevel@tonic-gate if (USBA_WRP2INTR_REQ(req_wrp)->
8720Sstevel@tonic-gate intr_completion_reason == USB_CR_OK) {
8730Sstevel@tonic-gate USBA_WRP2INTR_REQ(req_wrp)->
8740Sstevel@tonic-gate intr_completion_reason = req_wrp->wr_cr;
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate break;
8770Sstevel@tonic-gate case USB_EP_ATTR_BULK:
8780Sstevel@tonic-gate if (USBA_WRP2BULK_REQ(req_wrp)->
8790Sstevel@tonic-gate bulk_completion_reason == USB_CR_OK) {
8800Sstevel@tonic-gate USBA_WRP2BULK_REQ(req_wrp)->
8810Sstevel@tonic-gate bulk_completion_reason = req_wrp->wr_cr;
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate break;
8840Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
8850Sstevel@tonic-gate if (USBA_WRP2ISOC_REQ(req_wrp)->
8860Sstevel@tonic-gate isoc_completion_reason == USB_CR_OK) {
8870Sstevel@tonic-gate USBA_WRP2ISOC_REQ(req_wrp)->
8880Sstevel@tonic-gate isoc_completion_reason = req_wrp->wr_cr;
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate break;
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate if (req_wrp->wr_usb_flags & USBA_WRP_FLAGS_WAIT) {
8940Sstevel@tonic-gate cv_signal(&req_wrp->wr_cv);
8950Sstevel@tonic-gate if (ph_data->p_active_cntrl_req_wrp == (usb_opaque_t)req_wrp) {
8960Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp = NULL;
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
8990Sstevel@tonic-gate } else {
9000Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
9010Sstevel@tonic-gate switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
9020Sstevel@tonic-gate USB_EP_ATTR_MASK) {
9030Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
9040Sstevel@tonic-gate USBA_WRP2CTRL_REQ(req_wrp)->ctrl_exc_cb(pipe_handle,
9055773Sqz150045 USBA_WRP2CTRL_REQ(req_wrp));
9060Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
9070Sstevel@tonic-gate if (ph_data->p_active_cntrl_req_wrp ==
9080Sstevel@tonic-gate (usb_opaque_t)req_wrp) {
9090Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp = NULL;
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
9120Sstevel@tonic-gate break;
9130Sstevel@tonic-gate case USB_EP_ATTR_INTR:
9140Sstevel@tonic-gate USBA_WRP2INTR_REQ(req_wrp)->intr_exc_cb(pipe_handle,
9155773Sqz150045 USBA_WRP2INTR_REQ(req_wrp));
9160Sstevel@tonic-gate break;
9170Sstevel@tonic-gate case USB_EP_ATTR_BULK:
9180Sstevel@tonic-gate USBA_WRP2BULK_REQ(req_wrp)->bulk_exc_cb(pipe_handle,
9195773Sqz150045 USBA_WRP2BULK_REQ(req_wrp));
9200Sstevel@tonic-gate break;
9210Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
9220Sstevel@tonic-gate USBA_WRP2ISOC_REQ(req_wrp)->isoc_exc_cb(pipe_handle,
9235773Sqz150045 USBA_WRP2ISOC_REQ(req_wrp));
9240Sstevel@tonic-gate break;
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate /* we are done with this request */
9290Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
9300Sstevel@tonic-gate ph_data->p_req_count--;
9310Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
9320Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate * usba_do_req_exc_cb:
9380Sstevel@tonic-gate * called when flushing requests. rather than calling usba_req_exc_cb()
9390Sstevel@tonic-gate * directly, this function uses usba_hcdi_cb() which ensures callback
9400Sstevel@tonic-gate * order is preserved
9410Sstevel@tonic-gate */
9420Sstevel@tonic-gate void
usba_do_req_exc_cb(usba_req_wrapper_t * req_wrp,usb_cr_t cr,usb_cb_flags_t cb_flags)9430Sstevel@tonic-gate usba_do_req_exc_cb(usba_req_wrapper_t *req_wrp, usb_cr_t cr,
9440Sstevel@tonic-gate usb_cb_flags_t cb_flags)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate req_wrp->wr_cb_flags |= cb_flags;
9470Sstevel@tonic-gate usba_hcdi_cb(req_wrp->wr_ph_data, req_wrp->wr_req, cr);
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate /*
9520Sstevel@tonic-gate * usba_req_set_cb_flags:
9530Sstevel@tonic-gate * This function sets the request's callback flags to those stored in the
9540Sstevel@tonic-gate * request wrapper ORed with those received as an argument. Additionally
9550Sstevel@tonic-gate * USB_CB_INTR_CONTEXT is set if called from interrupt context.
9560Sstevel@tonic-gate *
9570Sstevel@tonic-gate * NOTE: The xfer may have succeeded, which client driver can determine
9580Sstevel@tonic-gate * by looking at usb_cr_t
9590Sstevel@tonic-gate */
9600Sstevel@tonic-gate void
usba_req_set_cb_flags(usba_req_wrapper_t * req_wrp,usb_cb_flags_t cb_flags)9610Sstevel@tonic-gate usba_req_set_cb_flags(usba_req_wrapper_t *req_wrp,
9620Sstevel@tonic-gate usb_cb_flags_t cb_flags)
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
9650Sstevel@tonic-gate "usba_req_set_cb_flags: wrp=0x%p cb-flags=0x%x",
9666898Sfb209375 (void *)req_wrp, cb_flags);
9670Sstevel@tonic-gate
9680Sstevel@tonic-gate cb_flags |= req_wrp->wr_cb_flags;
9690Sstevel@tonic-gate cb_flags = usba_check_intr_context(cb_flags);
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate /* do the callback under taskq context */
9720Sstevel@tonic-gate switch (req_wrp->wr_ph_data->p_ep.bmAttributes &
9730Sstevel@tonic-gate USB_EP_ATTR_MASK) {
9740Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
9750Sstevel@tonic-gate USBA_WRP2CTRL_REQ(req_wrp)->ctrl_cb_flags |= cb_flags;
9760Sstevel@tonic-gate break;
9770Sstevel@tonic-gate case USB_EP_ATTR_INTR:
9780Sstevel@tonic-gate USBA_WRP2INTR_REQ(req_wrp)->intr_cb_flags |= cb_flags;
9790Sstevel@tonic-gate break;
9800Sstevel@tonic-gate case USB_EP_ATTR_BULK:
9810Sstevel@tonic-gate USBA_WRP2BULK_REQ(req_wrp)->bulk_cb_flags |= cb_flags;
9820Sstevel@tonic-gate break;
9830Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
9840Sstevel@tonic-gate USBA_WRP2ISOC_REQ(req_wrp)->isoc_cb_flags |= cb_flags;
9850Sstevel@tonic-gate break;
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate
9900Sstevel@tonic-gate /*
9910Sstevel@tonic-gate * usba_pipe_sync_wait:
9920Sstevel@tonic-gate * wait for the request to finish.
9930Sstevel@tonic-gate * usba_hcdi_cb() does a cv_signal thru a soft intr
9940Sstevel@tonic-gate *
9950Sstevel@tonic-gate * Arguments:
9960Sstevel@tonic-gate * ph_data - pointer to pipe handle data
9970Sstevel@tonic-gate * wrp - pointer to usba_req_wrapper_structure.
9980Sstevel@tonic-gate *
9990Sstevel@tonic-gate * Return Values:
10000Sstevel@tonic-gate * USB_SUCCESS - request successfully executed
10010Sstevel@tonic-gate * USB_FAILURE - request failed
10020Sstevel@tonic-gate */
10030Sstevel@tonic-gate static int
usba_pipe_sync_wait(usba_pipe_handle_data_t * ph_data,usba_req_wrapper_t * wrp)10040Sstevel@tonic-gate usba_pipe_sync_wait(usba_pipe_handle_data_t *ph_data,
10050Sstevel@tonic-gate usba_req_wrapper_t *wrp)
10060Sstevel@tonic-gate {
10070Sstevel@tonic-gate ASSERT(wrp->wr_usb_flags & USB_FLAGS_SLEEP);
10080Sstevel@tonic-gate ASSERT(ph_data == wrp->wr_ph_data);
10090Sstevel@tonic-gate
10100Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
10110Sstevel@tonic-gate while (wrp->wr_done != B_TRUE) {
10120Sstevel@tonic-gate cv_wait(&wrp->wr_cv, &ph_data->p_mutex);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
10160Sstevel@tonic-gate
10170Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10186898Sfb209375 "usba_pipe_sync_wait: ph_data=0x%p cr=0x%x", (void *)ph_data,
10196898Sfb209375 wrp->wr_cr);
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate /* XXX return something better than USB_FAILURE?? */
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate return (wrp->wr_cr == USB_CR_OK ? USB_SUCCESS : USB_FAILURE);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate /*
10280Sstevel@tonic-gate * Allocate usb control request and a USB request wrapper
10290Sstevel@tonic-gate *
10300Sstevel@tonic-gate * Arguments:
10310Sstevel@tonic-gate * dip - dev_info_t of the client driver
10320Sstevel@tonic-gate * len - length of "data" for this control request
10330Sstevel@tonic-gate * flags:
10340Sstevel@tonic-gate * USB_FLAGS_SLEEP - Sleep if resources are not available
10350Sstevel@tonic-gate * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
10360Sstevel@tonic-gate *
10370Sstevel@tonic-gate * Return Values: usb_ctrl_req_t on success, NULL on failure
10380Sstevel@tonic-gate */
10390Sstevel@tonic-gate usb_ctrl_req_t *
usb_alloc_ctrl_req(dev_info_t * dip,size_t len,usb_flags_t flags)10400Sstevel@tonic-gate usb_alloc_ctrl_req(dev_info_t *dip,
10410Sstevel@tonic-gate size_t len,
10420Sstevel@tonic-gate usb_flags_t flags)
10430Sstevel@tonic-gate {
10440Sstevel@tonic-gate usb_ctrl_req_t *ctrl_req = NULL;
10450Sstevel@tonic-gate usba_req_wrapper_t *wrp;
10460Sstevel@tonic-gate
10470Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10480Sstevel@tonic-gate "usb_alloc_ctrl_req: dip=0x%p, wlen=0x%lx, flags=0x%x",
10496898Sfb209375 (void *)dip, len, flags);
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate /* Allocate + Initialize the usba_req_wrapper_t structure */
10520Sstevel@tonic-gate if (dip &&
10530Sstevel@tonic-gate ((wrp = usba_req_wrapper_alloc(dip, sizeof (*ctrl_req), flags)) !=
10540Sstevel@tonic-gate NULL)) {
10550Sstevel@tonic-gate ctrl_req = USBA_WRP2CTRL_REQ(wrp);
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate /* Allocate the usb_ctrl_req data mblk */
10580Sstevel@tonic-gate if (len) {
10590Sstevel@tonic-gate if (flags & USB_FLAGS_SLEEP) {
10600Sstevel@tonic-gate ctrl_req->ctrl_data = allocb_wait(len, BPRI_LO,
10615773Sqz150045 STR_NOSIG, NULL);
10620Sstevel@tonic-gate } else if ((ctrl_req->ctrl_data =
10630Sstevel@tonic-gate allocb(len, BPRI_HI)) == NULL) {
10640Sstevel@tonic-gate usba_req_wrapper_free(wrp);
10650Sstevel@tonic-gate ctrl_req = NULL;
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate }
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10716898Sfb209375 "usb_alloc_ctrl_req: ctrl_req = 0x%p", (void *)ctrl_req);
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate return (ctrl_req);
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate /*
10780Sstevel@tonic-gate * usb_free_ctrl_req:
10790Sstevel@tonic-gate * free USB control request + wrapper
10800Sstevel@tonic-gate *
10810Sstevel@tonic-gate * Arguments:
10820Sstevel@tonic-gate * req - pointer to usb_ctrl_req_t
10830Sstevel@tonic-gate */
10840Sstevel@tonic-gate void
usb_free_ctrl_req(usb_ctrl_req_t * req)10850Sstevel@tonic-gate usb_free_ctrl_req(usb_ctrl_req_t *req)
10860Sstevel@tonic-gate {
10870Sstevel@tonic-gate if (req) {
10880Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
10896898Sfb209375 "usb_free_ctrl_req: req = 0x%p", (void *)req);
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate if (req->ctrl_data) {
10920Sstevel@tonic-gate freemsg(req->ctrl_data);
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate usba_req_wrapper_free(USBA_REQ2WRP(req));
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate /*
11000Sstevel@tonic-gate * Client driver calls this function to issue the control
11010Sstevel@tonic-gate * request to the USBA
11020Sstevel@tonic-gate *
11030Sstevel@tonic-gate * Arguments:
11040Sstevel@tonic-gate * pipe_handle: control pipe pipehandle (obtained via usb_pipe_open()
11050Sstevel@tonic-gate * req: control request
11060Sstevel@tonic-gate * usb_flags:
11070Sstevel@tonic-gate * USB_FLAGS_SLEEP - wait for the request to complete
11080Sstevel@tonic-gate *
11090Sstevel@tonic-gate * Return Values:
11100Sstevel@tonic-gate * USB_SUCCESS - request successfully executed
11110Sstevel@tonic-gate * USB_FAILURE - request failed
11120Sstevel@tonic-gate */
11130Sstevel@tonic-gate int
usb_pipe_ctrl_xfer(usb_pipe_handle_t pipe_handle,usb_ctrl_req_t * req,usb_flags_t usb_flags)11140Sstevel@tonic-gate usb_pipe_ctrl_xfer(usb_pipe_handle_t pipe_handle,
11150Sstevel@tonic-gate usb_ctrl_req_t *req,
11160Sstevel@tonic-gate usb_flags_t usb_flags)
11170Sstevel@tonic-gate {
11180Sstevel@tonic-gate int rval;
11190Sstevel@tonic-gate usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
11200Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
11210Sstevel@tonic-gate usba_device_t *usba_device;
11220Sstevel@tonic-gate usb_flags_t wrp_usb_flags;
11230Sstevel@tonic-gate usb_pipe_state_t pipe_state;
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11260Sstevel@tonic-gate "usb_pipe_ctrl_xfer: req=0x%p, wrp=0x%p\n\t"
11270Sstevel@tonic-gate "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf=0x%x",
11286898Sfb209375 (void *)req, (void *)wrp, req->ctrl_bmRequestType,
11296898Sfb209375 req->ctrl_bRequest, req->ctrl_wValue, req->ctrl_wIndex,
11306898Sfb209375 req->ctrl_wLength, usb_flags);
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate if (ph_data == NULL) {
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate return (USB_INVALID_PIPE);
11350Sstevel@tonic-gate }
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
11380Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
11390Sstevel@tonic-gate
11400Sstevel@tonic-gate if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
11410Sstevel@tonic-gate USB_EP_ATTR_CONTROL)) != USB_SUCCESS) {
11420Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
11430Sstevel@tonic-gate "request rejected: rval=%d", rval);
11440Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
11470Sstevel@tonic-gate
11480Sstevel@tonic-gate return (rval);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate ASSERT(ph_data == wrp->wr_ph_data);
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate /* we accepted the request, so increment the req count */
11540Sstevel@tonic-gate ph_data->p_req_count++;
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate wrp_usb_flags = wrp->wr_usb_flags;
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate /* Get the current bulk pipe state */
11590Sstevel@tonic-gate pipe_state = usba_get_ph_state(ph_data);
11600Sstevel@tonic-gate
11610Sstevel@tonic-gate /*
11620Sstevel@tonic-gate * if this is for the default pipe, and the pipe is in error,
11630Sstevel@tonic-gate * just queue the request. autoclearing will start this request
11640Sstevel@tonic-gate *
11650Sstevel@tonic-gate * if there is already an active request in the queue
11660Sstevel@tonic-gate * then just add this request to the queue.
11670Sstevel@tonic-gate */
11680Sstevel@tonic-gate switch (pipe_state) {
11690Sstevel@tonic-gate case USB_PIPE_STATE_IDLE:
11700Sstevel@tonic-gate if (ph_data->p_queue.next ||
11710Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp) {
11720Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11736898Sfb209375 "usb_pipe_ctrl_xfer: queue request 0x%p",
11746898Sfb209375 (void *)req);
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
11770Sstevel@tonic-gate rval = USB_SUCCESS;
11780Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
11790Sstevel@tonic-gate } else {
11800Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
11810Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp = (usb_opaque_t)wrp;
11820Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
11830Sstevel@tonic-gate
11840Sstevel@tonic-gate /* issue the request to HCD */
11850Sstevel@tonic-gate rval = usba_device->usb_hcdi_ops->
11860Sstevel@tonic-gate usba_hcdi_pipe_ctrl_xfer(ph_data, req, usb_flags);
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate break;
11890Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE:
11900Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
11916898Sfb209375 "usb_pipe_ctrl_xfer: queue request 0x%p", (void *)req);
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
11940Sstevel@tonic-gate rval = USB_SUCCESS;
11950Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
11960Sstevel@tonic-gate break;
11970Sstevel@tonic-gate case USB_PIPE_STATE_ERROR:
11980Sstevel@tonic-gate if (USBA_IS_DEFAULT_PIPE(ph_data)) {
11990Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12000Sstevel@tonic-gate "usb_pipe_ctrl_xfer: queue request 0x%p on "
12016898Sfb209375 "pending def pipe error", (void *)req);
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
12040Sstevel@tonic-gate rval = USB_SUCCESS;
12050Sstevel@tonic-gate } else {
12060Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12070Sstevel@tonic-gate "usb_pipe_ctrl_xfer: pipe is in error state ");
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate rval = USB_PIPE_ERROR;
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
12120Sstevel@tonic-gate break;
12130Sstevel@tonic-gate default:
12140Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12150Sstevel@tonic-gate "usb_pipe_ctrl_xfer: pipe state %d", pipe_state);
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate rval = USB_PIPE_ERROR;
12180Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
12190Sstevel@tonic-gate break;
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate /* if there has been a failure, decrement req count */
12230Sstevel@tonic-gate if (rval != USB_SUCCESS) {
12240Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
12256898Sfb209375 "usb_pipe_ctrl_xfer: hcd failed req 0x%p", (void *)req);
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate if (req->ctrl_completion_reason == USB_CR_OK) {
12280Sstevel@tonic-gate req->ctrl_completion_reason = usba_rval2cr(rval);
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
12310Sstevel@tonic-gate ASSERT(wrp->wr_done == B_FALSE);
12320Sstevel@tonic-gate ph_data->p_req_count--;
12330Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
12340Sstevel@tonic-gate ph_data->p_active_cntrl_req_wrp = NULL;
12350Sstevel@tonic-gate if ((ph_data->p_req_count == 0) &&
12360Sstevel@tonic-gate (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
12370Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate /* if success and sleep specified, wait for completion */
12420Sstevel@tonic-gate } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
12430Sstevel@tonic-gate rval = usba_pipe_sync_wait(ph_data, wrp);
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
12470Sstevel@tonic-gate "usb_pipe_ctrl_xfer: rval=0x%x", rval);
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate return (rval);
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate /*
12560Sstevel@tonic-gate * usb_pipe_sync_ctrl_xfer():
12570Sstevel@tonic-gate * for simple synchronous control transactions this wrapper function
12580Sstevel@tonic-gate * will perform the allocation, xfer, and deallocation
12590Sstevel@tonic-gate * USB_ATTRS_AUTOCLEARING will be enabled
12600Sstevel@tonic-gate *
12610Sstevel@tonic-gate * Arguments:
12620Sstevel@tonic-gate * dip - pointer to clients devinfo
12630Sstevel@tonic-gate * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open()
12640Sstevel@tonic-gate * bmRequestType - characteristics of request
12650Sstevel@tonic-gate * bRequest - specific request
12660Sstevel@tonic-gate * wValue - varies according to request
12670Sstevel@tonic-gate * wIndex - index or offset
12680Sstevel@tonic-gate * wLength - number of bytes to xfer
12690Sstevel@tonic-gate * data - pointer to pointer to data and may be NULL if
12700Sstevel@tonic-gate * wLength is 0
12710Sstevel@tonic-gate * attrs - required request attributes
12720Sstevel@tonic-gate * completion_reason - completion status
12730Sstevel@tonic-gate * cb_flags - request completions flags
12740Sstevel@tonic-gate * flags - none
12750Sstevel@tonic-gate *
12760Sstevel@tonic-gate * Return Values:
12770Sstevel@tonic-gate * USB_SUCCESS - request successfully executed
12780Sstevel@tonic-gate * USB_* - request failed
12790Sstevel@tonic-gate *
12800Sstevel@tonic-gate * Notes:
12810Sstevel@tonic-gate * - in the case of failure, the client should check completion_reason and
12820Sstevel@tonic-gate * and cb_flags and determine further recovery action
12830Sstevel@tonic-gate * - the client should check data and if non-zero, free the data on
12840Sstevel@tonic-gate * completion
12850Sstevel@tonic-gate */
12860Sstevel@tonic-gate int
usb_pipe_sync_ctrl_xfer(dev_info_t * dip,usb_pipe_handle_t pipe_handle,uchar_t bmRequestType,uchar_t bRequest,uint16_t wValue,uint16_t wIndex,uint16_t wLength,mblk_t ** data,usb_req_attrs_t attributes,usb_cr_t * completion_reason,usb_cb_flags_t * cb_flags,usb_flags_t flags)12870Sstevel@tonic-gate usb_pipe_sync_ctrl_xfer(dev_info_t *dip,
12880Sstevel@tonic-gate usb_pipe_handle_t pipe_handle,
12890Sstevel@tonic-gate uchar_t bmRequestType,
12900Sstevel@tonic-gate uchar_t bRequest,
12910Sstevel@tonic-gate uint16_t wValue,
12920Sstevel@tonic-gate uint16_t wIndex,
12930Sstevel@tonic-gate uint16_t wLength,
12940Sstevel@tonic-gate mblk_t **data,
12950Sstevel@tonic-gate usb_req_attrs_t attributes,
12960Sstevel@tonic-gate usb_cr_t *completion_reason,
12970Sstevel@tonic-gate usb_cb_flags_t *cb_flags,
12980Sstevel@tonic-gate usb_flags_t flags)
12990Sstevel@tonic-gate {
13000Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data;
13010Sstevel@tonic-gate int rval;
13020Sstevel@tonic-gate usb_ctrl_req_t *ctrl_req;
13030Sstevel@tonic-gate size_t length;
13040Sstevel@tonic-gate #ifdef DEBUG
13050Sstevel@tonic-gate #define BUFSIZE 256
13060Sstevel@tonic-gate char *buf = kmem_alloc(BUFSIZE, KM_SLEEP);
13070Sstevel@tonic-gate #endif
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13100Sstevel@tonic-gate "usb_pipe_sync_ctrl_xfer: ph=0x%p\n\t"
13116898Sfb209375 "setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf = 0x%x", (void *)pipe_handle,
13120Sstevel@tonic-gate bmRequestType, bRequest, wValue, wIndex, wLength, flags);
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate if ((ph_data = usba_hold_ph_data(pipe_handle)) == NULL) {
13150Sstevel@tonic-gate rval = USB_INVALID_PIPE;
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate goto done;
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate if (servicing_interrupt()) {
13200Sstevel@tonic-gate rval = USB_INVALID_CONTEXT;
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate goto done;
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate if (dip == NULL) {
13250Sstevel@tonic-gate rval = USB_INVALID_ARGS;
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate goto done;
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate
13300Sstevel@tonic-gate length = ((data) && (*data)) ? 0: wLength;
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate ctrl_req = usb_alloc_ctrl_req(dip,
13330Sstevel@tonic-gate length, flags | USB_FLAGS_SLEEP);
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate /* Initialize the ctrl_req structure */
13360Sstevel@tonic-gate ctrl_req->ctrl_bmRequestType = bmRequestType;
13370Sstevel@tonic-gate ctrl_req->ctrl_bRequest = bRequest;
13380Sstevel@tonic-gate ctrl_req->ctrl_wValue = wValue;
13390Sstevel@tonic-gate ctrl_req->ctrl_wIndex = wIndex;
13400Sstevel@tonic-gate ctrl_req->ctrl_wLength = wLength;
13410Sstevel@tonic-gate ctrl_req->ctrl_data = ctrl_req->ctrl_data ?
13425773Sqz150045 ctrl_req->ctrl_data : ((data) ? *data : NULL);
13430Sstevel@tonic-gate ctrl_req->ctrl_timeout = USB_PIPE_TIMEOUT;
13440Sstevel@tonic-gate ctrl_req->ctrl_attributes = attributes | USB_ATTRS_AUTOCLEARING;
13450Sstevel@tonic-gate
13460Sstevel@tonic-gate /* Issue control xfer to the HCD */
13470Sstevel@tonic-gate rval = usb_pipe_ctrl_xfer(pipe_handle, ctrl_req,
13480Sstevel@tonic-gate flags | USB_FLAGS_SLEEP);
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate #ifdef DEBUG
13510Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
13520Sstevel@tonic-gate "req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s",
13536898Sfb209375 (void *)ctrl_req, usb_str_cr(ctrl_req->ctrl_completion_reason),
13540Sstevel@tonic-gate usb_str_cb_flags(ctrl_req->ctrl_cb_flags, buf, BUFSIZE),
13556898Sfb209375 (void *)ctrl_req->ctrl_data, usb_str_rval(rval));
13560Sstevel@tonic-gate #endif
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate /* copy back ctrl_req values */
13590Sstevel@tonic-gate if (data) {
13600Sstevel@tonic-gate *data = ctrl_req->ctrl_data;
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate if (completion_reason) {
13630Sstevel@tonic-gate *completion_reason = ctrl_req->ctrl_completion_reason;
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate if (cb_flags) {
13660Sstevel@tonic-gate *cb_flags = ctrl_req->ctrl_cb_flags;
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate /* Free up the control request now */
13700Sstevel@tonic-gate ctrl_req->ctrl_data = NULL; /* leave to client to free */
13710Sstevel@tonic-gate usb_free_ctrl_req(ctrl_req);
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate done:
13740Sstevel@tonic-gate #ifdef DEBUG
13750Sstevel@tonic-gate kmem_free(buf, BUFSIZE);
13760Sstevel@tonic-gate #endif
13770Sstevel@tonic-gate if (ph_data) {
13780Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
13790Sstevel@tonic-gate }
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate return (rval);
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate /*
13860Sstevel@tonic-gate * usb_pipe_ctrl_xfer_wait():
13870Sstevel@tonic-gate * Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer.
13880Sstevel@tonic-gate *
13890Sstevel@tonic-gate * ARGUMENTS:
13900Sstevel@tonic-gate * pipe_handle - control pipe pipehandle (obtained via usb_pipe_open())
13910Sstevel@tonic-gate * setup - setup descriptor params, attributes
13920Sstevel@tonic-gate * data - pointer to pointer to data and may be NULL when
13930Sstevel@tonic-gate * wLength is 0
13940Sstevel@tonic-gate * completion_reason - completion status.
13950Sstevel@tonic-gate * cb_flags - request completions flags.
13960Sstevel@tonic-gate * flags - none.
13970Sstevel@tonic-gate *
13980Sstevel@tonic-gate * RETURN VALUES:
13990Sstevel@tonic-gate * USB_SUCCESS - request successfully executed.
14000Sstevel@tonic-gate * USB_* - failure
14010Sstevel@tonic-gate */
14020Sstevel@tonic-gate int
usb_pipe_ctrl_xfer_wait(usb_pipe_handle_t pipe_handle,usb_ctrl_setup_t * setup,mblk_t ** data,usb_cr_t * completion_reason,usb_cb_flags_t * cb_flags,usb_flags_t flags)14030Sstevel@tonic-gate usb_pipe_ctrl_xfer_wait(
14040Sstevel@tonic-gate usb_pipe_handle_t pipe_handle,
14050Sstevel@tonic-gate usb_ctrl_setup_t *setup,
14060Sstevel@tonic-gate mblk_t **data,
14070Sstevel@tonic-gate usb_cr_t *completion_reason,
14080Sstevel@tonic-gate usb_cb_flags_t *cb_flags,
14090Sstevel@tonic-gate usb_flags_t flags)
14100Sstevel@tonic-gate {
14110Sstevel@tonic-gate return (usb_pipe_sync_ctrl_xfer(
14125773Sqz150045 usba_get_dip(pipe_handle),
14135773Sqz150045 pipe_handle,
14145773Sqz150045 setup->bmRequestType,
14155773Sqz150045 setup->bRequest,
14165773Sqz150045 setup->wValue,
14175773Sqz150045 setup->wIndex,
14185773Sqz150045 setup->wLength,
14195773Sqz150045 data,
14205773Sqz150045 setup->attrs,
14215773Sqz150045 completion_reason,
14225773Sqz150045 cb_flags,
14235773Sqz150045 flags));
14240Sstevel@tonic-gate }
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate /*
14280Sstevel@tonic-gate * usb_alloc_bulk_req:
14290Sstevel@tonic-gate * Allocate a usb bulk request + usba_req_wrapper_t
14300Sstevel@tonic-gate *
14310Sstevel@tonic-gate * Arguments:
14320Sstevel@tonic-gate * dip - dev_info_t of the client driver
14330Sstevel@tonic-gate * len - length of "data" for this bulk request
14340Sstevel@tonic-gate * flags:
14350Sstevel@tonic-gate * USB_FLAGS_SLEEP - Sleep if resources are not available
14360Sstevel@tonic-gate *
14370Sstevel@tonic-gate * Return Values:
14380Sstevel@tonic-gate * usb_bulk_req_t on success, NULL on failure
14390Sstevel@tonic-gate */
14400Sstevel@tonic-gate usb_bulk_req_t *
usb_alloc_bulk_req(dev_info_t * dip,size_t len,usb_flags_t flags)14410Sstevel@tonic-gate usb_alloc_bulk_req(dev_info_t *dip,
14420Sstevel@tonic-gate size_t len,
14430Sstevel@tonic-gate usb_flags_t flags)
14440Sstevel@tonic-gate {
14450Sstevel@tonic-gate usb_bulk_req_t *bulk_req = NULL;
14460Sstevel@tonic-gate usba_req_wrapper_t *wrp;
14470Sstevel@tonic-gate
14480Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14490Sstevel@tonic-gate "usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x",
14506898Sfb209375 (void *)dip, len, flags);
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate /* Allocate + Initialize the usba_req_wrapper_t structure */
14530Sstevel@tonic-gate if (dip &&
14540Sstevel@tonic-gate ((wrp = usba_req_wrapper_alloc(dip, sizeof (*bulk_req), flags)) !=
14550Sstevel@tonic-gate NULL)) {
14560Sstevel@tonic-gate bulk_req = USBA_WRP2BULK_REQ(wrp);
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate /* Allocate the usb_bulk_req data mblk */
14590Sstevel@tonic-gate if (len) {
14600Sstevel@tonic-gate if (flags & USB_FLAGS_SLEEP) {
14610Sstevel@tonic-gate bulk_req->bulk_data = allocb_wait(len,
14620Sstevel@tonic-gate BPRI_LO, STR_NOSIG, NULL);
14630Sstevel@tonic-gate } else if ((bulk_req->bulk_data =
14640Sstevel@tonic-gate allocb(len, BPRI_HI)) == NULL) {
14650Sstevel@tonic-gate usba_req_wrapper_free(wrp);
14660Sstevel@tonic-gate bulk_req = NULL;
14670Sstevel@tonic-gate }
14680Sstevel@tonic-gate }
14690Sstevel@tonic-gate
14700Sstevel@tonic-gate }
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14736898Sfb209375 "usb_alloc_bulk_req: bulk_req = 0x%p", (void *)bulk_req);
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate return (bulk_req);
14760Sstevel@tonic-gate }
14770Sstevel@tonic-gate
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * usb_free_bulk_req:
14810Sstevel@tonic-gate * free USB bulk request + wrapper
14820Sstevel@tonic-gate *
14830Sstevel@tonic-gate * Arguments:
14840Sstevel@tonic-gate * req - pointer to usb_bulk_req_t
14850Sstevel@tonic-gate */
14860Sstevel@tonic-gate void
usb_free_bulk_req(usb_bulk_req_t * req)14870Sstevel@tonic-gate usb_free_bulk_req(usb_bulk_req_t *req)
14880Sstevel@tonic-gate {
14890Sstevel@tonic-gate if (req) {
14900Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
14916898Sfb209375 "usb_free_bulk_req: req=0x%p", (void *)req);
14920Sstevel@tonic-gate
14930Sstevel@tonic-gate if (req->bulk_data) {
14940Sstevel@tonic-gate freemsg(req->bulk_data);
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate usba_req_wrapper_free(USBA_REQ2WRP(req));
14970Sstevel@tonic-gate }
14980Sstevel@tonic-gate }
14990Sstevel@tonic-gate
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate /*
15020Sstevel@tonic-gate * Client driver calls this function to issue the bulk xfer to the USBA
15030Sstevel@tonic-gate *
15040Sstevel@tonic-gate * Arguments:-
15050Sstevel@tonic-gate * pipe_handle - bulk pipe handle (obtained via usb_pipe_open()
15060Sstevel@tonic-gate * req - bulk data xfer request (IN or OUT)
15070Sstevel@tonic-gate * usb_flags - USB_FLAGS_SLEEP - wait for the request to complete
15080Sstevel@tonic-gate *
15090Sstevel@tonic-gate * Return Values:
15100Sstevel@tonic-gate * USB_SUCCESS - success
15110Sstevel@tonic-gate * USB_FAILURE - unspecified failure
15120Sstevel@tonic-gate */
15130Sstevel@tonic-gate int
usb_pipe_bulk_xfer(usb_pipe_handle_t pipe_handle,usb_bulk_req_t * req,usb_flags_t usb_flags)15140Sstevel@tonic-gate usb_pipe_bulk_xfer(usb_pipe_handle_t pipe_handle,
15150Sstevel@tonic-gate usb_bulk_req_t *req,
15160Sstevel@tonic-gate usb_flags_t usb_flags)
15170Sstevel@tonic-gate {
15180Sstevel@tonic-gate int rval;
15190Sstevel@tonic-gate usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
15200Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
15210Sstevel@tonic-gate usba_device_t *usba_device;
15220Sstevel@tonic-gate usb_flags_t wrp_usb_flags;
15230Sstevel@tonic-gate usb_pipe_state_t pipe_state;
15240Sstevel@tonic-gate
15250Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15266898Sfb209375 "usb_pipe_bulk_xfer: req=0x%p uf=0x%x", (void *)req, usb_flags);
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate if (ph_data == NULL) {
15290Sstevel@tonic-gate
15300Sstevel@tonic-gate return (USB_INVALID_PIPE);
15310Sstevel@tonic-gate }
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
15340Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
15350Sstevel@tonic-gate
15360Sstevel@tonic-gate if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
15370Sstevel@tonic-gate USB_EP_ATTR_BULK)) != USB_SUCCESS) {
15380Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
15390Sstevel@tonic-gate
15400Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
15410Sstevel@tonic-gate
15420Sstevel@tonic-gate return (rval);
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate
15450Sstevel@tonic-gate /* we accepted the request */
15460Sstevel@tonic-gate ph_data->p_req_count++;
15470Sstevel@tonic-gate wrp_usb_flags = wrp->wr_usb_flags;
15480Sstevel@tonic-gate
15490Sstevel@tonic-gate /* Get the current bulk pipe state */
15500Sstevel@tonic-gate pipe_state = usba_get_ph_state(ph_data);
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate /*
15530Sstevel@tonic-gate * if there is already an active request in the queue
15540Sstevel@tonic-gate * then just add this request to the queue.
15550Sstevel@tonic-gate */
15560Sstevel@tonic-gate switch (pipe_state) {
15570Sstevel@tonic-gate case USB_PIPE_STATE_IDLE:
15580Sstevel@tonic-gate if (ph_data->p_queue.next) {
15590Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15606898Sfb209375 "usb_pipe_bulk_xfer: queue request 0x%p",
15616898Sfb209375 (void *)req);
15620Sstevel@tonic-gate
15630Sstevel@tonic-gate usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
15640Sstevel@tonic-gate rval = USB_SUCCESS;
15650Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
15660Sstevel@tonic-gate } else {
15670Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
15680Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate /* issue the request to HCD */
15710Sstevel@tonic-gate rval = usba_device->usb_hcdi_ops->
15720Sstevel@tonic-gate usba_hcdi_pipe_bulk_xfer(ph_data, req, usb_flags);
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate break;
15750Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE:
15760Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15776898Sfb209375 "usb_pipe_bulk_xfer: queue request 0x%p", (void *)req);
15780Sstevel@tonic-gate
15790Sstevel@tonic-gate usba_add_to_list(&ph_data->p_queue, &wrp->wr_queue);
15800Sstevel@tonic-gate rval = USB_SUCCESS;
15810Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
15820Sstevel@tonic-gate break;
15830Sstevel@tonic-gate default:
15840Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
15850Sstevel@tonic-gate "usb_pipe_bulk_xfer: pipe state %d", pipe_state);
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate rval = USB_PIPE_ERROR;
15880Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
15890Sstevel@tonic-gate break;
15900Sstevel@tonic-gate }
15910Sstevel@tonic-gate
15920Sstevel@tonic-gate if (rval != USB_SUCCESS) {
15930Sstevel@tonic-gate if (req->bulk_completion_reason == USB_CR_OK) {
15940Sstevel@tonic-gate req->bulk_completion_reason = usba_rval2cr(rval);
15950Sstevel@tonic-gate }
15960Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
15970Sstevel@tonic-gate ASSERT(wrp->wr_done == B_FALSE);
15980Sstevel@tonic-gate ph_data->p_req_count--;
15990Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
16000Sstevel@tonic-gate if ((ph_data->p_req_count == 0) &&
16010Sstevel@tonic-gate (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
16020Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
16030Sstevel@tonic-gate }
16040Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
16050Sstevel@tonic-gate } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
16060Sstevel@tonic-gate rval = usba_pipe_sync_wait(ph_data, wrp);
16070Sstevel@tonic-gate }
16080Sstevel@tonic-gate
16090Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16100Sstevel@tonic-gate "usb_pipe_bulk_xfer: rval=%d", rval);
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
16130Sstevel@tonic-gate
16140Sstevel@tonic-gate return (rval);
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate
16170Sstevel@tonic-gate
16180Sstevel@tonic-gate /*
16190Sstevel@tonic-gate * usb_pipe_bulk_transfer_size:
16200Sstevel@tonic-gate * - request HCD to return bulk max transfer data size
16210Sstevel@tonic-gate *
16220Sstevel@tonic-gate * Arguments:
16230Sstevel@tonic-gate * dip - pointer to dev_info_t
16240Sstevel@tonic-gate * size - pointer to bulk_transfer_size
16250Sstevel@tonic-gate *
16260Sstevel@tonic-gate * Return Values:
16270Sstevel@tonic-gate * USB_SUCCESS - request successfully executed
16280Sstevel@tonic-gate * USB_FAILURE - request failed
16290Sstevel@tonic-gate */
16300Sstevel@tonic-gate int
usb_pipe_bulk_transfer_size(dev_info_t * dip,size_t * size)16310Sstevel@tonic-gate usb_pipe_bulk_transfer_size(dev_info_t *dip,
16320Sstevel@tonic-gate size_t *size)
16330Sstevel@tonic-gate {
16340Sstevel@tonic-gate return (usb_pipe_get_max_bulk_transfer_size(dip, size));
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate
16380Sstevel@tonic-gate int
usb_pipe_get_max_bulk_transfer_size(dev_info_t * dip,size_t * size)16390Sstevel@tonic-gate usb_pipe_get_max_bulk_transfer_size(dev_info_t *dip,
16400Sstevel@tonic-gate size_t *size)
16410Sstevel@tonic-gate {
16420Sstevel@tonic-gate usba_device_t *usba_device;
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate if ((dip == NULL) || (size == NULL)) {
16450Sstevel@tonic-gate
16460Sstevel@tonic-gate return (USB_INVALID_ARGS);
16470Sstevel@tonic-gate }
16480Sstevel@tonic-gate usba_device = usba_get_usba_device(dip);
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16516898Sfb209375 "usb_pipe_bulk_transfer_size: usba_device=0x%p",
16526898Sfb209375 (void *)usba_device);
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate if ((usba_device) &&
16550Sstevel@tonic-gate (usba_device->usb_hcdi_ops->usba_hcdi_bulk_transfer_size)) {
16560Sstevel@tonic-gate
16570Sstevel@tonic-gate return (usba_device->usb_hcdi_ops->
16580Sstevel@tonic-gate usba_hcdi_bulk_transfer_size(usba_device, size));
16590Sstevel@tonic-gate } else {
16600Sstevel@tonic-gate *size = 0;
16610Sstevel@tonic-gate
16620Sstevel@tonic-gate return (USB_FAILURE);
16630Sstevel@tonic-gate }
16640Sstevel@tonic-gate }
16650Sstevel@tonic-gate
16660Sstevel@tonic-gate
16670Sstevel@tonic-gate /*
16680Sstevel@tonic-gate * usb_alloc_intr_req:
16690Sstevel@tonic-gate * Allocate usb interrupt request
16700Sstevel@tonic-gate *
16710Sstevel@tonic-gate * Arguments:
16720Sstevel@tonic-gate * dip - dev_info_t of the client driver
16730Sstevel@tonic-gate * len - length of "data" for this interrupt request
16740Sstevel@tonic-gate * flags -
16750Sstevel@tonic-gate * USB_FLAGS_SLEEP - Sleep if resources are not available
16760Sstevel@tonic-gate *
16770Sstevel@tonic-gate * Return Values:
16780Sstevel@tonic-gate * usb_intr_req_t on success, NULL on failure
16790Sstevel@tonic-gate */
16800Sstevel@tonic-gate usb_intr_req_t *
usb_alloc_intr_req(dev_info_t * dip,size_t len,usb_flags_t flags)16810Sstevel@tonic-gate usb_alloc_intr_req(dev_info_t *dip,
16820Sstevel@tonic-gate size_t len,
16830Sstevel@tonic-gate usb_flags_t flags)
16840Sstevel@tonic-gate {
16850Sstevel@tonic-gate usb_intr_req_t *intr_req = NULL;
16860Sstevel@tonic-gate usba_req_wrapper_t *wrp;
16870Sstevel@tonic-gate
16880Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
16890Sstevel@tonic-gate "usb_alloc_intr_req: dip=0x%p, len=0x%lx, flags=0x%x",
16906898Sfb209375 (void *)dip, len, flags);
16910Sstevel@tonic-gate
16920Sstevel@tonic-gate /* Allocate + Initialize the usba_req_wrapper_t structure */
16930Sstevel@tonic-gate if ((dip &&
16940Sstevel@tonic-gate (wrp = usba_req_wrapper_alloc(dip, sizeof (*intr_req), flags)) !=
16950Sstevel@tonic-gate NULL)) {
16960Sstevel@tonic-gate intr_req = (usb_intr_req_t *)USBA_WRP2INTR_REQ(wrp);
16970Sstevel@tonic-gate
16980Sstevel@tonic-gate /* Allocate the usb_intr_req data mblk */
16990Sstevel@tonic-gate if (len) {
17000Sstevel@tonic-gate if (flags & USB_FLAGS_SLEEP) {
17010Sstevel@tonic-gate intr_req->intr_data = allocb_wait(len, BPRI_LO,
17025773Sqz150045 STR_NOSIG, NULL);
17030Sstevel@tonic-gate } else if ((intr_req->intr_data =
17040Sstevel@tonic-gate allocb(len, BPRI_HI)) == NULL) {
17050Sstevel@tonic-gate usba_req_wrapper_free(wrp);
17060Sstevel@tonic-gate intr_req = NULL;
17070Sstevel@tonic-gate }
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate }
17100Sstevel@tonic-gate
17110Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
17126898Sfb209375 "usb_alloc_intr_req: intr_req=0x%p", (void *)intr_req);
17130Sstevel@tonic-gate
17140Sstevel@tonic-gate return (intr_req);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate
17180Sstevel@tonic-gate /*
17190Sstevel@tonic-gate * usba_hcdi_dup_intr_req:
17200Sstevel@tonic-gate * create duplicate of interrupt request
17210Sstevel@tonic-gate *
17220Sstevel@tonic-gate * Arguments:
17230Sstevel@tonic-gate * dip - devinfo pointer
17240Sstevel@tonic-gate * reqp - original requestp pointer
17250Sstevel@tonic-gate * len - length of "data" for this interrupt request
17260Sstevel@tonic-gate * flags -
17270Sstevel@tonic-gate * USB_FLAGS_SLEEP - Sleep if resources are not available
17280Sstevel@tonic-gate *
17290Sstevel@tonic-gate * Return Values:
17300Sstevel@tonic-gate * usb_intr_req_t on success, NULL on failure
17310Sstevel@tonic-gate */
17320Sstevel@tonic-gate usb_intr_req_t *
usba_hcdi_dup_intr_req(dev_info_t * dip,usb_intr_req_t * reqp,size_t len,usb_flags_t flags)17330Sstevel@tonic-gate usba_hcdi_dup_intr_req(
17340Sstevel@tonic-gate dev_info_t *dip,
17350Sstevel@tonic-gate usb_intr_req_t *reqp,
17360Sstevel@tonic-gate size_t len,
17370Sstevel@tonic-gate usb_flags_t flags)
17380Sstevel@tonic-gate {
17390Sstevel@tonic-gate usb_intr_req_t *intr_reqp = NULL;
17400Sstevel@tonic-gate usba_req_wrapper_t *intr_wrp, *req_wrp;
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate if (reqp == NULL) {
17430Sstevel@tonic-gate
17440Sstevel@tonic-gate return (NULL);
17450Sstevel@tonic-gate }
17460Sstevel@tonic-gate
17470Sstevel@tonic-gate req_wrp = USBA_REQ2WRP(reqp);
17480Sstevel@tonic-gate
17490Sstevel@tonic-gate if (((intr_reqp = usb_alloc_intr_req(dip, len, flags)) != NULL)) {
17500Sstevel@tonic-gate intr_reqp->intr_client_private = reqp->intr_client_private;
17510Sstevel@tonic-gate intr_reqp->intr_timeout = reqp->intr_timeout;
17520Sstevel@tonic-gate intr_reqp->intr_attributes = reqp->intr_attributes;
17530Sstevel@tonic-gate intr_reqp->intr_len = reqp->intr_len;
17540Sstevel@tonic-gate intr_reqp->intr_cb = reqp->intr_cb;
17550Sstevel@tonic-gate intr_reqp->intr_exc_cb = reqp->intr_exc_cb;
17560Sstevel@tonic-gate
17570Sstevel@tonic-gate intr_wrp = USBA_REQ2WRP(intr_reqp);
17580Sstevel@tonic-gate intr_wrp->wr_dip = req_wrp->wr_dip;
17590Sstevel@tonic-gate intr_wrp->wr_ph_data = req_wrp->wr_ph_data;
17600Sstevel@tonic-gate intr_wrp->wr_attrs = req_wrp->wr_attrs;
17610Sstevel@tonic-gate intr_wrp->wr_usb_flags = req_wrp->wr_usb_flags;
17620Sstevel@tonic-gate }
17630Sstevel@tonic-gate
17640Sstevel@tonic-gate return (intr_reqp);
17650Sstevel@tonic-gate }
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate
17680Sstevel@tonic-gate /*
17690Sstevel@tonic-gate * usb_free_intr_req:
17700Sstevel@tonic-gate * free USB intr request + wrapper
17710Sstevel@tonic-gate *
17720Sstevel@tonic-gate * Arguments:
17730Sstevel@tonic-gate * req - pointer to usb_intr_req_t
17740Sstevel@tonic-gate */
17750Sstevel@tonic-gate void
usb_free_intr_req(usb_intr_req_t * req)17760Sstevel@tonic-gate usb_free_intr_req(usb_intr_req_t *req)
17770Sstevel@tonic-gate {
17780Sstevel@tonic-gate if (req) {
17790Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
17806898Sfb209375 "usb_free_intr_req: req = 0x%p", (void *)req);
17810Sstevel@tonic-gate
17820Sstevel@tonic-gate if (req->intr_data) {
17830Sstevel@tonic-gate freemsg(req->intr_data);
17840Sstevel@tonic-gate }
17850Sstevel@tonic-gate
17860Sstevel@tonic-gate usba_req_wrapper_free(USBA_REQ2WRP(req));
17870Sstevel@tonic-gate }
17880Sstevel@tonic-gate }
17890Sstevel@tonic-gate
17900Sstevel@tonic-gate
17910Sstevel@tonic-gate /*
17920Sstevel@tonic-gate * Client driver calls this function to issue the intr xfer to the USBA
17930Sstevel@tonic-gate *
17940Sstevel@tonic-gate * Arguments:-
17950Sstevel@tonic-gate * pipe_handle - intr pipe handle (obtained via usb_pipe_open()
17960Sstevel@tonic-gate * req - intr data xfer request (IN or OUT)
17970Sstevel@tonic-gate * flags -
17980Sstevel@tonic-gate * USB_FLAGS_SLEEP - wait for the request to complete
17990Sstevel@tonic-gate * Return Values
18000Sstevel@tonic-gate * USB_SUCCESS - success
18010Sstevel@tonic-gate * USB_FAILURE - unspecified failure
18020Sstevel@tonic-gate */
18030Sstevel@tonic-gate int
usb_pipe_intr_xfer(usb_pipe_handle_t pipe_handle,usb_intr_req_t * req,usb_flags_t usb_flags)18040Sstevel@tonic-gate usb_pipe_intr_xfer(usb_pipe_handle_t pipe_handle,
18050Sstevel@tonic-gate usb_intr_req_t *req,
18060Sstevel@tonic-gate usb_flags_t usb_flags)
18070Sstevel@tonic-gate {
18080Sstevel@tonic-gate int rval;
18090Sstevel@tonic-gate usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
18100Sstevel@tonic-gate usba_ph_impl_t *ph_impl = (usba_ph_impl_t *)pipe_handle;
18110Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
18120Sstevel@tonic-gate usba_device_t *usba_device;
18130Sstevel@tonic-gate uchar_t direction;
18140Sstevel@tonic-gate usb_flags_t wrp_usb_flags;
18150Sstevel@tonic-gate usb_pipe_state_t pipe_state;
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
18180Sstevel@tonic-gate "usb_pipe_intr_req: req=0x%p uf=0x%x",
18196898Sfb209375 (void *)req, usb_flags);
18200Sstevel@tonic-gate
18210Sstevel@tonic-gate if (ph_data == NULL) {
18220Sstevel@tonic-gate
18230Sstevel@tonic-gate return (USB_INVALID_PIPE);
18240Sstevel@tonic-gate }
18250Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
18260Sstevel@tonic-gate direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
18270Sstevel@tonic-gate
18280Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
18290Sstevel@tonic-gate if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, usb_flags,
18300Sstevel@tonic-gate USB_EP_ATTR_INTR)) != USB_SUCCESS) {
18310Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
18320Sstevel@tonic-gate
18330Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate return (rval);
18360Sstevel@tonic-gate }
18370Sstevel@tonic-gate
18380Sstevel@tonic-gate /* Get the current interrupt pipe state */
18390Sstevel@tonic-gate pipe_state = usba_get_ph_state(ph_data);
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate switch (pipe_state) {
18420Sstevel@tonic-gate case USB_PIPE_STATE_IDLE:
18430Sstevel@tonic-gate /*
18440Sstevel@tonic-gate * if the pipe state is in middle of transition,
18450Sstevel@tonic-gate * i.e. stop polling is in progress, fail any
18460Sstevel@tonic-gate * attempt to do a start polling
18470Sstevel@tonic-gate */
18480Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
18490Sstevel@tonic-gate if (ph_impl->usba_ph_state_changing > 0) {
18500Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
18530Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
18560Sstevel@tonic-gate "usb_pipe_intr_req: fail request - "
18570Sstevel@tonic-gate "stop polling in progress");
18580Sstevel@tonic-gate
18590Sstevel@tonic-gate return (USB_FAILURE);
18600Sstevel@tonic-gate } else {
18610Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
18620Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate
18650Sstevel@tonic-gate break;
18660Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE:
18670Sstevel@tonic-gate /*
18680Sstevel@tonic-gate * If this is interrupt IN pipe and if we are
18690Sstevel@tonic-gate * already polling, return failure.
18700Sstevel@tonic-gate */
18710Sstevel@tonic-gate if (direction == USB_EP_DIR_IN) {
18720Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI,
18730Sstevel@tonic-gate usbai_log_handle,
18740Sstevel@tonic-gate "usb_pipe_intr_req: already polling");
18750Sstevel@tonic-gate
18760Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
18770Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
18780Sstevel@tonic-gate
18790Sstevel@tonic-gate return (USB_FAILURE);
18800Sstevel@tonic-gate }
18810Sstevel@tonic-gate
18820Sstevel@tonic-gate break;
18830Sstevel@tonic-gate default:
18840Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
18850Sstevel@tonic-gate "usb_pipe_intr_req: pipe state %d", pipe_state);
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
18880Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
18890Sstevel@tonic-gate
18900Sstevel@tonic-gate return (USB_PIPE_ERROR);
18910Sstevel@tonic-gate }
18920Sstevel@tonic-gate
18930Sstevel@tonic-gate /* we accept the request */
18940Sstevel@tonic-gate wrp_usb_flags = wrp->wr_usb_flags;
18950Sstevel@tonic-gate ph_data->p_req_count++;
18960Sstevel@tonic-gate
18970Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
18980Sstevel@tonic-gate
18990Sstevel@tonic-gate /* issue the request out */
19000Sstevel@tonic-gate if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_intr_xfer(ph_data,
19010Sstevel@tonic-gate req, usb_flags)) != USB_SUCCESS) {
19020Sstevel@tonic-gate
19030Sstevel@tonic-gate /* the request failed, decrement the ref_count */
19040Sstevel@tonic-gate if (req->intr_completion_reason == USB_CR_OK) {
19050Sstevel@tonic-gate req->intr_completion_reason = usba_rval2cr(rval);
19060Sstevel@tonic-gate }
19070Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
19080Sstevel@tonic-gate ASSERT(wrp->wr_done == B_FALSE);
19090Sstevel@tonic-gate ph_data->p_req_count--;
19100Sstevel@tonic-gate ASSERT(ph_data->p_req_count >= 0);
19110Sstevel@tonic-gate if ((ph_data->p_req_count == 0) &&
19120Sstevel@tonic-gate (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
19130Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
19140Sstevel@tonic-gate }
19150Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
19160Sstevel@tonic-gate
19170Sstevel@tonic-gate /* if sleep specified, wait for completion */
19180Sstevel@tonic-gate } else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
19190Sstevel@tonic-gate rval = usba_pipe_sync_wait(ph_data, wrp);
19200Sstevel@tonic-gate }
19210Sstevel@tonic-gate
19220Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
19230Sstevel@tonic-gate "usb_pipe_intr_req: rval=0x%x", rval);
19240Sstevel@tonic-gate
19250Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
19260Sstevel@tonic-gate
19270Sstevel@tonic-gate return (rval);
19280Sstevel@tonic-gate }
19290Sstevel@tonic-gate
19300Sstevel@tonic-gate
19310Sstevel@tonic-gate /*
19320Sstevel@tonic-gate * usba_pipe_sync_stop_intr_polling:
19330Sstevel@tonic-gate * - set up for sync transport, if necessary
19340Sstevel@tonic-gate * - request HCD to stop polling
19350Sstevel@tonic-gate * - wait for draining of all callbacks
19360Sstevel@tonic-gate */
19370Sstevel@tonic-gate /*ARGSUSED*/
19380Sstevel@tonic-gate static int
usba_pipe_sync_stop_intr_polling(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)19390Sstevel@tonic-gate usba_pipe_sync_stop_intr_polling(dev_info_t *dip,
19400Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
19410Sstevel@tonic-gate usba_pipe_async_req_t *request,
19420Sstevel@tonic-gate usb_flags_t flags)
19430Sstevel@tonic-gate {
19440Sstevel@tonic-gate int rval;
19450Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data;
19460Sstevel@tonic-gate usba_device_t *usba_device;
19470Sstevel@tonic-gate
19480Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
19490Sstevel@tonic-gate "usba_pipe_sync_stop_intr_polling: flags=0x%x", flags);
19500Sstevel@tonic-gate
19510Sstevel@tonic-gate ph_data = usba_get_ph_data((usb_pipe_handle_t)ph_impl);
19520Sstevel@tonic-gate if (ph_data == NULL) {
19530Sstevel@tonic-gate usba_release_ph_data(ph_impl);
19540Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
19550Sstevel@tonic-gate "usba_pipe_sync_stop_intr_polling: pipe closed");
19560Sstevel@tonic-gate
19570Sstevel@tonic-gate return (USB_INVALID_PIPE);
19580Sstevel@tonic-gate }
19590Sstevel@tonic-gate
19600Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
19610Sstevel@tonic-gate
19620Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
19630Sstevel@tonic-gate
19640Sstevel@tonic-gate if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
19650Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
19660Sstevel@tonic-gate "usba_pipe_sync_stop_intr_polling: pipe error");
19670Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate usba_release_ph_data(ph_impl);
19700Sstevel@tonic-gate
19710Sstevel@tonic-gate return (USB_PIPE_ERROR);
19720Sstevel@tonic-gate }
19730Sstevel@tonic-gate
19740Sstevel@tonic-gate if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
19750Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
19760Sstevel@tonic-gate "usba_pipe_sync_stop_intr_polling: already idle");
19770Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
19780Sstevel@tonic-gate
19790Sstevel@tonic-gate usba_release_ph_data(ph_impl);
19800Sstevel@tonic-gate
19810Sstevel@tonic-gate return (USB_SUCCESS);
19820Sstevel@tonic-gate }
19830Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
19840Sstevel@tonic-gate
19850Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
19860Sstevel@tonic-gate ph_impl->usba_ph_state_changing++;
19870Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
19880Sstevel@tonic-gate
19890Sstevel@tonic-gate flags |= USB_FLAGS_SLEEP;
19900Sstevel@tonic-gate
19910Sstevel@tonic-gate for (;;) {
19920Sstevel@tonic-gate rval = usba_device->usb_hcdi_ops->
19935773Sqz150045 usba_hcdi_pipe_stop_intr_polling(ph_data, flags);
19940Sstevel@tonic-gate
19950Sstevel@tonic-gate /*
19960Sstevel@tonic-gate * The host controller has stopped polling of the endpoint.
19970Sstevel@tonic-gate * Now, drain the callbacks if there are any on the callback
19980Sstevel@tonic-gate * queue.
19990Sstevel@tonic-gate */
20000Sstevel@tonic-gate if (rval == USB_SUCCESS) {
20010Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
20020Sstevel@tonic-gate
20030Sstevel@tonic-gate /*
20040Sstevel@tonic-gate * there is a tiny window that the client driver
20050Sstevel@tonic-gate * may still have restarted the polling and we
20060Sstevel@tonic-gate * have to let the stop polling win)
20070Sstevel@tonic-gate */
20080Sstevel@tonic-gate rval = usba_drain_cbs(ph_data, 0,
20095773Sqz150045 USB_CR_STOPPED_POLLING);
20100Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
20110Sstevel@tonic-gate if (rval != USB_SUCCESS) {
20120Sstevel@tonic-gate
20130Sstevel@tonic-gate continue;
20140Sstevel@tonic-gate }
20150Sstevel@tonic-gate }
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate break;
20180Sstevel@tonic-gate }
20190Sstevel@tonic-gate
20200Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
20210Sstevel@tonic-gate "usba_pipe_sync_stop_intr_polling: rval=0x%x", rval);
20220Sstevel@tonic-gate
20230Sstevel@tonic-gate mutex_enter(&ph_impl->usba_ph_mutex);
20240Sstevel@tonic-gate ph_impl->usba_ph_state_changing--;
20250Sstevel@tonic-gate mutex_exit(&ph_impl->usba_ph_mutex);
20260Sstevel@tonic-gate
20270Sstevel@tonic-gate usba_release_ph_data(ph_impl);
20280Sstevel@tonic-gate
20290Sstevel@tonic-gate return (rval);
20300Sstevel@tonic-gate }
20310Sstevel@tonic-gate
20320Sstevel@tonic-gate
20330Sstevel@tonic-gate /*
20340Sstevel@tonic-gate * dummy callback function for stop polling
20350Sstevel@tonic-gate */
20360Sstevel@tonic-gate static void
usba_dummy_callback(usb_pipe_handle_t ph,usb_opaque_t arg,int rval,usb_cb_flags_t flags)20370Sstevel@tonic-gate usba_dummy_callback(
20380Sstevel@tonic-gate usb_pipe_handle_t ph,
20390Sstevel@tonic-gate usb_opaque_t arg,
20400Sstevel@tonic-gate int rval,
20410Sstevel@tonic-gate usb_cb_flags_t flags)
20420Sstevel@tonic-gate {
20430Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
20440Sstevel@tonic-gate "usba_dummy_callback: "
20450Sstevel@tonic-gate "ph=0x%p rval=0x%x flags=0x%x cb_arg=0x%p",
20466898Sfb209375 (void *)ph, rval, flags, (void *)arg);
20470Sstevel@tonic-gate }
20480Sstevel@tonic-gate
20490Sstevel@tonic-gate
20500Sstevel@tonic-gate /*
20510Sstevel@tonic-gate * usb_pipe_stop_intr_polling:
20520Sstevel@tonic-gate * stop polling for interrupt pipe IN data
20530Sstevel@tonic-gate * The HCD doesn't do a usba_hcdi_cb().
20540Sstevel@tonic-gate * It just returns success/failure
20550Sstevel@tonic-gate * Arguments:
20560Sstevel@tonic-gate * pipe_handle - pipe handle
20570Sstevel@tonic-gate * flags -
20580Sstevel@tonic-gate * USB_FLAGS_SLEEP: wait for completion
20590Sstevel@tonic-gate */
20600Sstevel@tonic-gate void
usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,usb_flags_t flags)20610Sstevel@tonic-gate usb_pipe_stop_intr_polling(usb_pipe_handle_t pipe_handle,
20620Sstevel@tonic-gate usb_flags_t flags)
20630Sstevel@tonic-gate {
20640Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
20670Sstevel@tonic-gate "usba_pipe_stop_intr_polling: flags=0x%x", flags);
20680Sstevel@tonic-gate
20690Sstevel@tonic-gate if (ph_data == NULL) {
20700Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20710Sstevel@tonic-gate "usba_pipe_stop_intr_polling: pipe closed");
20720Sstevel@tonic-gate
20730Sstevel@tonic-gate return;
20740Sstevel@tonic-gate }
20750Sstevel@tonic-gate
20760Sstevel@tonic-gate if ((ph_data->p_ep.bmAttributes &
20770Sstevel@tonic-gate USB_EP_ATTR_MASK) != USB_EP_ATTR_INTR) {
2078978Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20790Sstevel@tonic-gate "usba_pipe_stop_intr_polling: wrong pipe type");
20800Sstevel@tonic-gate
20810Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate return;
20840Sstevel@tonic-gate }
20850Sstevel@tonic-gate
20860Sstevel@tonic-gate if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2087978Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20880Sstevel@tonic-gate "usba_pipe_stop_intr_polling: wrong pipe direction");
20890Sstevel@tonic-gate
20900Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate return;
20930Sstevel@tonic-gate }
20940Sstevel@tonic-gate
20950Sstevel@tonic-gate if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2096978Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
20970Sstevel@tonic-gate "usba_pipe_stop_intr_polling: invalid context");
20980Sstevel@tonic-gate
20990Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
21000Sstevel@tonic-gate
21010Sstevel@tonic-gate return;
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate
21040Sstevel@tonic-gate (void) usba_pipe_setup_func_call(ph_data->p_dip,
21050Sstevel@tonic-gate usba_pipe_sync_stop_intr_polling,
21060Sstevel@tonic-gate (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
21070Sstevel@tonic-gate flags, usba_dummy_callback, NULL);
21080Sstevel@tonic-gate }
21090Sstevel@tonic-gate
21100Sstevel@tonic-gate
21110Sstevel@tonic-gate /*
21120Sstevel@tonic-gate * usb_alloc_isoc_req:
21130Sstevel@tonic-gate * - Allocate usb isochronous resources that includes usb isochronous
21140Sstevel@tonic-gate * request and array of packet descriptor structures and wrapper.
21150Sstevel@tonic-gate *
21160Sstevel@tonic-gate * Arguments:
21170Sstevel@tonic-gate * dip - dev_info_t of the client driver
21180Sstevel@tonic-gate * isoc_pkts_count - number of isoc_pkt_descr_t's
21190Sstevel@tonic-gate * len - length of "data" for this isochronous request
21200Sstevel@tonic-gate * flags -
21210Sstevel@tonic-gate * USB_FLAGS_SLEEP - Sleep if resources are not available
21220Sstevel@tonic-gate * no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
21230Sstevel@tonic-gate *
21240Sstevel@tonic-gate * Return Values:
21250Sstevel@tonic-gate * usb_isoc_req_t on success, NULL on failure
21260Sstevel@tonic-gate */
21270Sstevel@tonic-gate /*ARGSUSED*/
21280Sstevel@tonic-gate usb_isoc_req_t *
usb_alloc_isoc_req(dev_info_t * dip,uint_t isoc_pkts_count,size_t len,usb_flags_t flags)21290Sstevel@tonic-gate usb_alloc_isoc_req(dev_info_t *dip,
21300Sstevel@tonic-gate uint_t isoc_pkts_count,
21310Sstevel@tonic-gate size_t len,
21320Sstevel@tonic-gate usb_flags_t flags)
21330Sstevel@tonic-gate {
21340Sstevel@tonic-gate usb_isoc_req_t *isoc_req = NULL;
21350Sstevel@tonic-gate usba_req_wrapper_t *wrp;
21360Sstevel@tonic-gate size_t length = sizeof (*isoc_req) +
21375773Sqz150045 (sizeof (usb_isoc_pkt_descr_t) * isoc_pkts_count);
21380Sstevel@tonic-gate
21390Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
21400Sstevel@tonic-gate "usb_alloc_isoc_req: dip=0x%p pkt_cnt=%d len=%lu flags=0x%x",
21416898Sfb209375 (void *)dip, isoc_pkts_count, len, flags);
21420Sstevel@tonic-gate
21430Sstevel@tonic-gate /* client needs to set isoc_pks_count */
21440Sstevel@tonic-gate if (dip && isoc_pkts_count) {
21450Sstevel@tonic-gate /* Allocate + Initialize the usba_req_wrapper_t structure */
21460Sstevel@tonic-gate if ((wrp = usba_req_wrapper_alloc(dip, length, flags)) !=
21470Sstevel@tonic-gate NULL) {
21480Sstevel@tonic-gate isoc_req = (usb_isoc_req_t *)USBA_WRP2ISOC_REQ(wrp);
21490Sstevel@tonic-gate
21500Sstevel@tonic-gate /* Allocate the usb_isoc_req data mblk */
21510Sstevel@tonic-gate if (len) {
21520Sstevel@tonic-gate if ((isoc_req->isoc_data =
21530Sstevel@tonic-gate allocb(len, BPRI_HI)) == NULL) {
21540Sstevel@tonic-gate usba_req_wrapper_free(wrp);
21550Sstevel@tonic-gate isoc_req = NULL;
21560Sstevel@tonic-gate }
21570Sstevel@tonic-gate }
21580Sstevel@tonic-gate }
21590Sstevel@tonic-gate }
21600Sstevel@tonic-gate
21610Sstevel@tonic-gate if (isoc_req) {
21620Sstevel@tonic-gate isoc_req->isoc_pkt_descr = (usb_isoc_pkt_descr_t *)
21630Sstevel@tonic-gate (((intptr_t)isoc_req) + (sizeof (usb_isoc_req_t)));
21640Sstevel@tonic-gate
21650Sstevel@tonic-gate /* Initialize all the fields of usb isochronous request */
2166*7492SZhigang.Lu@Sun.COM isoc_req->isoc_pkts_count = (ushort_t)isoc_pkts_count;
21670Sstevel@tonic-gate }
21680Sstevel@tonic-gate
21690Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
21706898Sfb209375 "usb_alloc_isoc_req: isoc_req = 0x%p", (void *)isoc_req);
21710Sstevel@tonic-gate
21720Sstevel@tonic-gate return (isoc_req);
21730Sstevel@tonic-gate }
21740Sstevel@tonic-gate
21750Sstevel@tonic-gate
21760Sstevel@tonic-gate /*
21770Sstevel@tonic-gate * usba_hcdi_dup_isoc_req:
21780Sstevel@tonic-gate * create duplicate of isoc request
21790Sstevel@tonic-gate *
21800Sstevel@tonic-gate * Arguments:
21810Sstevel@tonic-gate * dip - devinfo pointer
21820Sstevel@tonic-gate * reqp - original request pointer
21830Sstevel@tonic-gate * len - length of "data" for this isoc request
21840Sstevel@tonic-gate * flags -
21850Sstevel@tonic-gate * USB_FLAGS_SLEEP - Sleep if resources are not available
21860Sstevel@tonic-gate *
21870Sstevel@tonic-gate * Return Values:
21880Sstevel@tonic-gate * usb_isoc_req_t on success, NULL on failure
21890Sstevel@tonic-gate */
21900Sstevel@tonic-gate usb_isoc_req_t *
usba_hcdi_dup_isoc_req(dev_info_t * dip,usb_isoc_req_t * reqp,usb_flags_t flags)21910Sstevel@tonic-gate usba_hcdi_dup_isoc_req(
21920Sstevel@tonic-gate dev_info_t *dip,
21930Sstevel@tonic-gate usb_isoc_req_t *reqp,
21940Sstevel@tonic-gate usb_flags_t flags)
21950Sstevel@tonic-gate {
21960Sstevel@tonic-gate usb_isoc_req_t *isoc_reqp = NULL;
21970Sstevel@tonic-gate usba_req_wrapper_t *isoc_wrp, *req_wrp;
21980Sstevel@tonic-gate ushort_t count;
21990Sstevel@tonic-gate ushort_t isoc_pkts_count;
22000Sstevel@tonic-gate size_t length;
22010Sstevel@tonic-gate
22020Sstevel@tonic-gate if (reqp == NULL) {
22030Sstevel@tonic-gate
22040Sstevel@tonic-gate return (isoc_reqp);
22050Sstevel@tonic-gate }
22060Sstevel@tonic-gate
22070Sstevel@tonic-gate isoc_pkts_count = reqp->isoc_pkts_count;
22080Sstevel@tonic-gate
22090Sstevel@tonic-gate /* calculate total data length required in original request */
22100Sstevel@tonic-gate for (count = length = 0; count < isoc_pkts_count; count++) {
22110Sstevel@tonic-gate length += reqp->isoc_pkt_descr[count].isoc_pkt_length;
22120Sstevel@tonic-gate }
22130Sstevel@tonic-gate
22140Sstevel@tonic-gate req_wrp = USBA_REQ2WRP(reqp);
22150Sstevel@tonic-gate
22160Sstevel@tonic-gate if (((isoc_reqp = usb_alloc_isoc_req(dip,
22170Sstevel@tonic-gate isoc_pkts_count, length, flags)) != NULL)) {
22180Sstevel@tonic-gate isoc_reqp->isoc_frame_no = reqp->isoc_frame_no;
22190Sstevel@tonic-gate isoc_reqp->isoc_pkts_count = reqp->isoc_pkts_count;
22200Sstevel@tonic-gate isoc_reqp->isoc_pkts_length = reqp->isoc_pkts_length;
22210Sstevel@tonic-gate isoc_reqp->isoc_attributes = reqp->isoc_attributes;
22220Sstevel@tonic-gate isoc_reqp->isoc_client_private = reqp->isoc_client_private;
22230Sstevel@tonic-gate isoc_reqp->isoc_cb = reqp->isoc_cb;
22240Sstevel@tonic-gate isoc_reqp->isoc_exc_cb = reqp->isoc_exc_cb;
22250Sstevel@tonic-gate
22260Sstevel@tonic-gate isoc_wrp = USBA_REQ2WRP(isoc_reqp);
22270Sstevel@tonic-gate isoc_wrp->wr_dip = req_wrp->wr_dip;
22280Sstevel@tonic-gate isoc_wrp->wr_ph_data = req_wrp->wr_ph_data;
22290Sstevel@tonic-gate isoc_wrp->wr_attrs = req_wrp->wr_attrs;
22300Sstevel@tonic-gate isoc_wrp->wr_usb_flags = req_wrp->wr_usb_flags;
22310Sstevel@tonic-gate
22320Sstevel@tonic-gate for (count = 0; count < isoc_pkts_count; count++) {
22330Sstevel@tonic-gate isoc_reqp->isoc_pkt_descr[count].isoc_pkt_length =
22345773Sqz150045 reqp->isoc_pkt_descr[count].isoc_pkt_length;
22350Sstevel@tonic-gate }
22360Sstevel@tonic-gate }
22370Sstevel@tonic-gate
22380Sstevel@tonic-gate return (isoc_reqp);
22390Sstevel@tonic-gate }
22400Sstevel@tonic-gate
22410Sstevel@tonic-gate
22420Sstevel@tonic-gate /*
22430Sstevel@tonic-gate * usb_free_isoc_req:
22440Sstevel@tonic-gate * - Deallocate usb isochronous resources that includes usb isochronous
22450Sstevel@tonic-gate * request and array of packet descriptor strcutures.
22460Sstevel@tonic-gate *
22470Sstevel@tonic-gate * Arguments:
22480Sstevel@tonic-gate * req - pointer to usb_isoc_req_t
22490Sstevel@tonic-gate */
22500Sstevel@tonic-gate void
usb_free_isoc_req(usb_isoc_req_t * req)22510Sstevel@tonic-gate usb_free_isoc_req(usb_isoc_req_t *req)
22520Sstevel@tonic-gate {
22530Sstevel@tonic-gate if (req) {
22540Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
22556898Sfb209375 "usb_free_isoc_req: req=0x%p", (void *)req);
22560Sstevel@tonic-gate
22570Sstevel@tonic-gate if (req->isoc_data) {
22580Sstevel@tonic-gate freemsg(req->isoc_data);
22590Sstevel@tonic-gate }
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate usba_req_wrapper_free(USBA_REQ2WRP(req));
22620Sstevel@tonic-gate }
22630Sstevel@tonic-gate }
22640Sstevel@tonic-gate
22650Sstevel@tonic-gate
22660Sstevel@tonic-gate /*
22670Sstevel@tonic-gate * usb_get_current_frame_number:
22680Sstevel@tonic-gate * - request HCD to return current usb frame number
22690Sstevel@tonic-gate *
22700Sstevel@tonic-gate * Arguments:
22710Sstevel@tonic-gate * dip - pointer to dev_info_t
22720Sstevel@tonic-gate *
22730Sstevel@tonic-gate * Return Values:
22740Sstevel@tonic-gate * current_frame_number - request successfully executed
22750Sstevel@tonic-gate * 0 - request failed
22760Sstevel@tonic-gate */
22770Sstevel@tonic-gate usb_frame_number_t
usb_get_current_frame_number(dev_info_t * dip)22780Sstevel@tonic-gate usb_get_current_frame_number(dev_info_t *dip)
22790Sstevel@tonic-gate {
22800Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
22816898Sfb209375 "usb_get_current_frame_number: dip=0x%p", (void *)dip);
22820Sstevel@tonic-gate
22830Sstevel@tonic-gate if (dip) {
22840Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
22855773Sqz150045 usb_frame_number_t frame_number;
22860Sstevel@tonic-gate
22870Sstevel@tonic-gate if (usba_device->usb_hcdi_ops->
22880Sstevel@tonic-gate usba_hcdi_get_current_frame_number) {
22890Sstevel@tonic-gate
22905773Sqz150045 if (usba_device->usb_hcdi_ops->
22915773Sqz150045 usba_hcdi_get_current_frame_number(usba_device,
22925773Sqz150045 &frame_number) == USB_SUCCESS) {
22935773Sqz150045
22945773Sqz150045 return (frame_number);
22955773Sqz150045 }
22960Sstevel@tonic-gate }
22970Sstevel@tonic-gate }
22980Sstevel@tonic-gate
22990Sstevel@tonic-gate return (0);
23000Sstevel@tonic-gate }
23010Sstevel@tonic-gate
23020Sstevel@tonic-gate
23030Sstevel@tonic-gate /*
23040Sstevel@tonic-gate * usb_get_max_isoc_pkts:
23050Sstevel@tonic-gate * - request HCD to return maximum isochronous packets per request
23060Sstevel@tonic-gate *
23070Sstevel@tonic-gate * Arguments:
23080Sstevel@tonic-gate * dip - pointer to dev_info_t
23090Sstevel@tonic-gate *
23100Sstevel@tonic-gate * Return Values:
23110Sstevel@tonic-gate * isoc_pkt - request successfully executed
23120Sstevel@tonic-gate * 0 - request failed
23130Sstevel@tonic-gate */
23140Sstevel@tonic-gate uint_t
usb_get_max_isoc_pkts(dev_info_t * dip)23150Sstevel@tonic-gate usb_get_max_isoc_pkts(dev_info_t *dip)
23160Sstevel@tonic-gate {
23170Sstevel@tonic-gate return (usb_get_max_pkts_per_isoc_request(dip));
23180Sstevel@tonic-gate }
23190Sstevel@tonic-gate
23200Sstevel@tonic-gate
23210Sstevel@tonic-gate uint_t
usb_get_max_pkts_per_isoc_request(dev_info_t * dip)23220Sstevel@tonic-gate usb_get_max_pkts_per_isoc_request(dev_info_t *dip)
23230Sstevel@tonic-gate {
23240Sstevel@tonic-gate if (dip) {
23250Sstevel@tonic-gate usba_device_t *usba_device = usba_get_usba_device(dip);
23265773Sqz150045 uint_t max_isoc_pkts_per_request;
23270Sstevel@tonic-gate
23280Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
23296898Sfb209375 "usb_get_max_isoc_pkts: usba_device=0x%p",
23306898Sfb209375 (void *)usba_device);
23310Sstevel@tonic-gate
23320Sstevel@tonic-gate if (usba_device->usb_hcdi_ops->usba_hcdi_get_max_isoc_pkts) {
23330Sstevel@tonic-gate
23345773Sqz150045 if (usba_device->usb_hcdi_ops->
23355773Sqz150045 usba_hcdi_get_max_isoc_pkts(usba_device,
23365773Sqz150045 &max_isoc_pkts_per_request) == USB_SUCCESS) {
23375773Sqz150045
23385773Sqz150045 return (max_isoc_pkts_per_request);
23395773Sqz150045 }
23400Sstevel@tonic-gate }
23410Sstevel@tonic-gate }
23420Sstevel@tonic-gate
23430Sstevel@tonic-gate return (0);
23440Sstevel@tonic-gate }
23450Sstevel@tonic-gate
23460Sstevel@tonic-gate
23470Sstevel@tonic-gate /*
23480Sstevel@tonic-gate * usb_pipe_isoc_xfer:
23490Sstevel@tonic-gate * - check for pipe stalled
23500Sstevel@tonic-gate * - request HCD to transport isoc data asynchronously
23510Sstevel@tonic-gate *
23520Sstevel@tonic-gate * Arguments:
23530Sstevel@tonic-gate * pipe_handle - isoc pipe pipehandle (obtained via usb_pipe_open())
23540Sstevel@tonic-gate * req - isochronous request
23550Sstevel@tonic-gate *
23560Sstevel@tonic-gate * Return Values:
23570Sstevel@tonic-gate * USB_SUCCESS - request successfully executed
23580Sstevel@tonic-gate * USB_FAILURE - request failed
23590Sstevel@tonic-gate */
23600Sstevel@tonic-gate int
usb_pipe_isoc_xfer(usb_pipe_handle_t pipe_handle,usb_isoc_req_t * req,usb_flags_t flags)23610Sstevel@tonic-gate usb_pipe_isoc_xfer(usb_pipe_handle_t pipe_handle,
23620Sstevel@tonic-gate usb_isoc_req_t *req,
23630Sstevel@tonic-gate usb_flags_t flags)
23640Sstevel@tonic-gate {
23650Sstevel@tonic-gate int rval;
23660Sstevel@tonic-gate usba_req_wrapper_t *wrp = USBA_REQ2WRP(req);
23670Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
23680Sstevel@tonic-gate usba_device_t *usba_device;
23690Sstevel@tonic-gate uchar_t direction;
23700Sstevel@tonic-gate usb_pipe_state_t pipe_state;
23710Sstevel@tonic-gate
23720Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
23730Sstevel@tonic-gate "usb_pipe_isoc_xfer: flags=0x%x", flags);
23740Sstevel@tonic-gate
23750Sstevel@tonic-gate if (ph_data == NULL) {
23760Sstevel@tonic-gate
23770Sstevel@tonic-gate return (USB_INVALID_PIPE);
23780Sstevel@tonic-gate }
23790Sstevel@tonic-gate
23800Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
23810Sstevel@tonic-gate direction = ph_data->p_ep.bEndpointAddress & USB_EP_DIR_MASK;
23820Sstevel@tonic-gate
23830Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
23840Sstevel@tonic-gate if ((rval = usba_check_req(ph_data, (usb_opaque_t)req, flags,
23850Sstevel@tonic-gate USB_EP_ATTR_ISOCH)) != USB_SUCCESS) {
23860Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
23870Sstevel@tonic-gate
23880Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
23890Sstevel@tonic-gate
23900Sstevel@tonic-gate return (rval);
23910Sstevel@tonic-gate }
23920Sstevel@tonic-gate
23930Sstevel@tonic-gate req->isoc_error_count = 0;
23940Sstevel@tonic-gate
23950Sstevel@tonic-gate /* Get the current isoch pipe state */
23960Sstevel@tonic-gate pipe_state = usba_get_ph_state(ph_data);
23970Sstevel@tonic-gate
23980Sstevel@tonic-gate switch (pipe_state) {
23990Sstevel@tonic-gate case USB_PIPE_STATE_IDLE:
24000Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_ACTIVE);
24010Sstevel@tonic-gate break;
24020Sstevel@tonic-gate case USB_PIPE_STATE_ACTIVE:
24030Sstevel@tonic-gate if (direction == USB_EP_DIR_IN) {
24040Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI,
24050Sstevel@tonic-gate usbai_log_handle,
24060Sstevel@tonic-gate "usb_pipe_isoc_req: already polling");
24070Sstevel@tonic-gate
24080Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
24090Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
24100Sstevel@tonic-gate
24110Sstevel@tonic-gate return (USB_FAILURE);
24120Sstevel@tonic-gate }
24130Sstevel@tonic-gate break;
24140Sstevel@tonic-gate default:
24150Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
24160Sstevel@tonic-gate "usb_pipe_isoc_req: pipe state %d", pipe_state);
24170Sstevel@tonic-gate
24180Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
24190Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
24200Sstevel@tonic-gate
24210Sstevel@tonic-gate return (USB_PIPE_ERROR);
24220Sstevel@tonic-gate }
24230Sstevel@tonic-gate
24240Sstevel@tonic-gate /* we accept the request */
24250Sstevel@tonic-gate ph_data->p_req_count++;
24260Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
24270Sstevel@tonic-gate
24280Sstevel@tonic-gate if ((rval = usba_device->usb_hcdi_ops->usba_hcdi_pipe_isoc_xfer(
24290Sstevel@tonic-gate ph_data, req, flags)) != USB_SUCCESS) {
24300Sstevel@tonic-gate if (req->isoc_completion_reason == USB_CR_OK) {
24310Sstevel@tonic-gate req->isoc_completion_reason = usba_rval2cr(rval);
24320Sstevel@tonic-gate }
24330Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
24340Sstevel@tonic-gate ASSERT(wrp->wr_done == B_FALSE);
24350Sstevel@tonic-gate ph_data->p_req_count--;
24360Sstevel@tonic-gate if ((ph_data->p_req_count == 0) &&
24370Sstevel@tonic-gate (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ACTIVE)) {
24380Sstevel@tonic-gate usba_pipe_new_state(ph_data, USB_PIPE_STATE_IDLE);
24390Sstevel@tonic-gate }
24400Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
24410Sstevel@tonic-gate }
24420Sstevel@tonic-gate
24430Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
24440Sstevel@tonic-gate "usb_pipe_isoc_req: rval=%x", rval);
24450Sstevel@tonic-gate
24460Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
24470Sstevel@tonic-gate
24480Sstevel@tonic-gate return (rval);
24490Sstevel@tonic-gate }
24500Sstevel@tonic-gate
24510Sstevel@tonic-gate
24520Sstevel@tonic-gate /*
24530Sstevel@tonic-gate * usba_pipe_sync_stop_isoc_polling:
24540Sstevel@tonic-gate * - set up for sync transport, if necessary
24550Sstevel@tonic-gate * - request HCD to stop polling
24560Sstevel@tonic-gate * - wait for draining of all callbacks
24570Sstevel@tonic-gate *
24580Sstevel@tonic-gate * Arguments:
24590Sstevel@tonic-gate * dip - dev_info pointer
24600Sstevel@tonic-gate * pipe_handle - pointer to pipe handle
24610Sstevel@tonic-gate * flags - USB_FLAGS_SLEEP: wait for completion
24620Sstevel@tonic-gate */
24630Sstevel@tonic-gate /*ARGSUSED*/
24640Sstevel@tonic-gate static int
usba_pipe_sync_stop_isoc_polling(dev_info_t * dip,usba_ph_impl_t * ph_impl,usba_pipe_async_req_t * request,usb_flags_t flags)24650Sstevel@tonic-gate usba_pipe_sync_stop_isoc_polling(dev_info_t *dip,
24660Sstevel@tonic-gate usba_ph_impl_t *ph_impl,
24670Sstevel@tonic-gate usba_pipe_async_req_t *request,
24680Sstevel@tonic-gate usb_flags_t flags)
24690Sstevel@tonic-gate {
24700Sstevel@tonic-gate int rval;
24710Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_get_ph_data(
24725773Sqz150045 (usb_pipe_handle_t)ph_impl);
24730Sstevel@tonic-gate usba_device_t *usba_device;
24740Sstevel@tonic-gate
24750Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
24760Sstevel@tonic-gate "usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags);
24770Sstevel@tonic-gate
24780Sstevel@tonic-gate if (ph_data == NULL) {
24790Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
24800Sstevel@tonic-gate "usba_pipe_stop_isoc_polling: pipe closed");
24810Sstevel@tonic-gate
24820Sstevel@tonic-gate return (USB_INVALID_PIPE);
24830Sstevel@tonic-gate }
24840Sstevel@tonic-gate
24850Sstevel@tonic-gate usba_device = ph_data->p_usba_device;
24860Sstevel@tonic-gate
24870Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
24880Sstevel@tonic-gate
24890Sstevel@tonic-gate if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_ERROR) {
24900Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
24910Sstevel@tonic-gate "usba_pipe_sync_stop_isoc_polling: pipe error");
24920Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
24930Sstevel@tonic-gate
24940Sstevel@tonic-gate usba_release_ph_data(ph_impl);
24950Sstevel@tonic-gate
24960Sstevel@tonic-gate return (USB_PIPE_ERROR);
24970Sstevel@tonic-gate }
24980Sstevel@tonic-gate
24990Sstevel@tonic-gate if (usba_get_ph_state(ph_data) == USB_PIPE_STATE_IDLE) {
25000Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25010Sstevel@tonic-gate "usba_pipe_sync_stop_isoc_polling: already stopped");
25020Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
25030Sstevel@tonic-gate
25040Sstevel@tonic-gate usba_release_ph_data(ph_impl);
25050Sstevel@tonic-gate
25060Sstevel@tonic-gate return (USB_SUCCESS);
25070Sstevel@tonic-gate }
25080Sstevel@tonic-gate
25090Sstevel@tonic-gate
25100Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
25110Sstevel@tonic-gate
25120Sstevel@tonic-gate flags |= USB_FLAGS_SLEEP;
25130Sstevel@tonic-gate
25140Sstevel@tonic-gate for (;;) {
25150Sstevel@tonic-gate rval = usba_device->usb_hcdi_ops->
25165773Sqz150045 usba_hcdi_pipe_stop_isoc_polling(ph_data, flags);
25170Sstevel@tonic-gate
25180Sstevel@tonic-gate /*
25190Sstevel@tonic-gate * The host controller has stopped polling of the endpoint.
25200Sstevel@tonic-gate * Now, drain the callbacks if there are any on the callback
25210Sstevel@tonic-gate * queue.
25220Sstevel@tonic-gate */
25230Sstevel@tonic-gate if (rval == USB_SUCCESS) {
25240Sstevel@tonic-gate mutex_enter(&ph_data->p_mutex);
25250Sstevel@tonic-gate
25260Sstevel@tonic-gate /*
25270Sstevel@tonic-gate * there is a tiny window that the client driver
25280Sstevel@tonic-gate * may still have restarted the polling and we
25290Sstevel@tonic-gate * let the stop polling win
25300Sstevel@tonic-gate */
25310Sstevel@tonic-gate rval = usba_drain_cbs(ph_data, 0,
25325773Sqz150045 USB_CR_STOPPED_POLLING);
25330Sstevel@tonic-gate mutex_exit(&ph_data->p_mutex);
25340Sstevel@tonic-gate if (rval != USB_SUCCESS) {
25350Sstevel@tonic-gate
25360Sstevel@tonic-gate continue;
25370Sstevel@tonic-gate }
25380Sstevel@tonic-gate }
25390Sstevel@tonic-gate
25400Sstevel@tonic-gate break;
25410Sstevel@tonic-gate }
25420Sstevel@tonic-gate
25430Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
25440Sstevel@tonic-gate "usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval);
25450Sstevel@tonic-gate
25460Sstevel@tonic-gate usba_release_ph_data(ph_impl);
25470Sstevel@tonic-gate
25480Sstevel@tonic-gate return (rval);
25490Sstevel@tonic-gate }
25500Sstevel@tonic-gate
25510Sstevel@tonic-gate
25520Sstevel@tonic-gate /*
25530Sstevel@tonic-gate * usb_pipe_stop_isoc_polling:
25540Sstevel@tonic-gate * stop polling for isoc IN data
25550Sstevel@tonic-gate *
25560Sstevel@tonic-gate * Arguments:
25570Sstevel@tonic-gate * pipe_handle - pipe handle
25580Sstevel@tonic-gate * flags -
25590Sstevel@tonic-gate * USB_FLAGS_SLEEP: wait for completion
25600Sstevel@tonic-gate */
25610Sstevel@tonic-gate void
usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,usb_flags_t flags)25620Sstevel@tonic-gate usb_pipe_stop_isoc_polling(usb_pipe_handle_t pipe_handle,
25630Sstevel@tonic-gate usb_flags_t flags)
25640Sstevel@tonic-gate {
25650Sstevel@tonic-gate usba_pipe_handle_data_t *ph_data = usba_hold_ph_data(pipe_handle);
25660Sstevel@tonic-gate
25670Sstevel@tonic-gate USB_DPRINTF_L4(DPRINT_MASK_USBAI, usbai_log_handle,
25680Sstevel@tonic-gate "usba_pipe_stop_isoc_polling: uf=0x%x", flags);
25690Sstevel@tonic-gate
25700Sstevel@tonic-gate if (ph_data == NULL) {
25710Sstevel@tonic-gate USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25720Sstevel@tonic-gate "usba_pipe_stop_isoc_polling: pipe closed");
25730Sstevel@tonic-gate
25740Sstevel@tonic-gate return;
25750Sstevel@tonic-gate }
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate if ((ph_data->p_ep.bmAttributes & USB_EP_ATTR_MASK) !=
25780Sstevel@tonic-gate USB_EP_ATTR_ISOCH) {
2579978Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25800Sstevel@tonic-gate "usba_pipe_stop_isoc_polling: wrong pipe type");
25810Sstevel@tonic-gate
25820Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
25830Sstevel@tonic-gate
25840Sstevel@tonic-gate return;
25850Sstevel@tonic-gate }
25860Sstevel@tonic-gate if ((ph_data->p_ep.bEndpointAddress & USB_EP_DIR_IN) == 0) {
2587978Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25880Sstevel@tonic-gate "usba_pipe_stop_isoc_polling: wrong pipe direction");
25890Sstevel@tonic-gate
25900Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
25910Sstevel@tonic-gate
25920Sstevel@tonic-gate return;
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate
25950Sstevel@tonic-gate if (servicing_interrupt() && (flags & USB_FLAGS_SLEEP)) {
2596978Sfrits USB_DPRINTF_L2(DPRINT_MASK_USBAI, usbai_log_handle,
25970Sstevel@tonic-gate "usba_pipe_stop_intr_polling: invalid context");
25980Sstevel@tonic-gate
25990Sstevel@tonic-gate usba_release_ph_data(ph_data->p_ph_impl);
26000Sstevel@tonic-gate
26010Sstevel@tonic-gate return;
26020Sstevel@tonic-gate }
26030Sstevel@tonic-gate
26040Sstevel@tonic-gate (void) usba_pipe_setup_func_call(ph_data->p_dip,
26050Sstevel@tonic-gate usba_pipe_sync_stop_isoc_polling,
26060Sstevel@tonic-gate (usba_ph_impl_t *)pipe_handle, (usb_opaque_t)flags,
26070Sstevel@tonic-gate flags, usba_dummy_callback, NULL);
26080Sstevel@tonic-gate }
2609