/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* USBA: Solaris USB Architecture support
*
* functions that deal with allocation/free/data_xfers
* usb_alloc_ctrl_req()
* usb_free_ctrl_req()
* usb_pipe_ctrl_xfer()
* usb_pipe_sync_ctrl_xfer()
* usb_pipe_ctrl_xfer_wait()
*
* usb_alloc_bulk_req()
* usb_free_bulk_req()
* usb_pipe_bulk_xfer()
* usb_pipe_bulk_transfer_size()
*
* usb_alloc_intr_req()
* usb_free_intr_req()
* usb_pipe_intr_xfer()
* usb_pipe_stop_intr_polling()
*
* usb_alloc_isoc_req()
* usb_free_isoc_req()
* usb_get_current_frame_number()
* usb_get_max_isoc_pkts()
* usb_pipe_isoc_xfer()
* usb_pipe_stop_isoc_polling()
*
* XXX to do:
* update return values where needed
* keep track of requests not freed
*
*/
#define USBA_FRAMEWORK
/* prototypes */
static int usba_flags_attr_check(usba_pipe_handle_data_t *,
/*
* usba_check_req:
* check pipe, request structure for validity
*
* Arguments:
* ph - pipe handle pointer
* req - opaque request pointer
* flags - usb flags
*
* Returns:
* USB_SUCCESS - valid request
* USB_INVALID_REQUEST - request contains some invalid values
* USB_PIPE_ERROR - pipe is in error state
* USB_INVALID_CONTEXT - sleep in interrupt context
* USB_INVALID_PIPE - zero pipe or wrong pipe
*/
static int
{
if (rval != USB_SUCCESS) {
"usba_check_req: ph_data=0x%p req=0x%p flags=0%x rval=%d",
}
return (rval);
}
static int
{
int n;
"usba_check_req: ph_data=0x%p req=0x%p flags=0x%x",
return (USB_INVALID_ARGS);
}
/* set completion reason first so it specifies an error */
switch (ep_attrs) {
case USB_EP_ATTR_CONTROL:
break;
case USB_EP_ATTR_BULK:
break;
case USB_EP_ATTR_INTR:
break;
case USB_EP_ATTR_ISOCH:
break;
}
return (USB_INVALID_CONTEXT);
}
return (USB_INVALID_PIPE);
}
/* we must have usba_device and default ph to do autoclearing */
return (USB_INVALID_PIPE);
}
/* check if this is a valid request packet, ie. not freed */
return (USB_INVALID_REQUEST);
}
/* copy over some members for easy checking later */
switch (ep_attrs) {
case USB_EP_ATTR_CONTROL:
if (flags & USB_FLAGS_SLEEP) {
}
/* force auto clearing on the default pipe */
if (USBA_IS_DEFAULT_PIPE(ph_data)) {
}
break;
case USB_EP_ATTR_BULK:
if (flags & USB_FLAGS_SLEEP) {
}
break;
case USB_EP_ATTR_INTR:
if ((flags & USB_FLAGS_SLEEP) &&
(attrs & USB_ATTRS_ONE_XFER)) {
}
break;
case USB_EP_ATTR_ISOCH:
break;
}
/* check flags and attr combinations */
USB_SUCCESS) {
return (USB_INVALID_REQUEST);
}
/* if no sleep, there must be callback ptrs */
if ((flags & USB_FLAGS_SLEEP) == 0) {
return (USB_INVALID_REQUEST);
}
}
switch (ep_attrs) {
case USB_EP_ATTR_CONTROL:
return (USB_INVALID_REQUEST);
}
break;
case USB_EP_ATTR_BULK:
return (USB_INVALID_REQUEST);
}
break;
case USB_EP_ATTR_INTR:
if (direction == USB_EP_DIR_OUT) {
return (USB_INVALID_REQUEST);
}
}
if (direction == USB_EP_DIR_IN) {
return (USB_INVALID_REQUEST);
}
}
return (USB_INVALID_REQUEST);
}
(timeout > 0)) {
return (USB_INVALID_REQUEST);
}
}
break;
case USB_EP_ATTR_ISOCH:
if (direction == USB_EP_DIR_IN) {
return (USB_INVALID_REQUEST);
}
}
return (USB_INVALID_REQUEST);
}
/*
* real isoc_pkts_length, it should be checked.
*/
if (direction == USB_EP_DIR_OUT) {
return (USB_INVALID_REQUEST);
}
}
/* special isoc checks */
if ((isoc_req->isoc_pkts_count == 0) ||
return (USB_INVALID_REQUEST);
}
/* check attributes for conflicts, one must be specified */
if (!((isoc_req->isoc_attributes &
return (USB_NO_FRAME_NUMBER);
}
/* both may not be specified */
if ((isoc_req->isoc_attributes &
return (USB_NO_FRAME_NUMBER);
}
/* no start frame may be specified for ASAP attribute */
return (USB_INVALID_REQUEST);
}
/* start frame must be specified for START FRAME attribute */
if (((isoc_req->isoc_attributes &
(isoc_req->isoc_frame_no == 0)) {
return (USB_NO_FRAME_NUMBER);
}
/* each packet must have initialized pkt length */
for (n = 0; n < isoc_req->isoc_pkts_count; n++) {
return (USB_INVALID_REQUEST);
}
}
break;
}
/* save pipe_handle/attrs/timeout/usb_flags */
/* zero some fields in case the request is reused */
/* this request looks good */
return (USB_SUCCESS);
}
/*
* Table of invalid flags and attributes values. See "usbai.h"
* for a complete table on valid usb_req_attrs_t
*/
#define X ((uint_t)(-1))
struct flags_attr {
} usb_invalid_flags_attrs[] = {
{ X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_START_FRAME },
{ X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_START_FRAME },
{ X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_START_FRAME },
{ X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ISOC_XFER_ASAP },
{ X, USB_EP_ATTR_INTR, X, USB_ATTRS_ISOC_XFER_ASAP },
{ X, USB_EP_ATTR_BULK, X, USB_ATTRS_ISOC_XFER_ASAP },
{ X, USB_EP_ATTR_CONTROL, X, USB_ATTRS_ONE_XFER },
{ X, USB_EP_ATTR_BULK, X, USB_ATTRS_ONE_XFER },
{ X, USB_EP_ATTR_ISOCH, X, USB_ATTRS_ONE_XFER },
};
sizeof (struct flags_attr)
/*
* function to check flags and attribute combinations for a particular pipe
* Arguments:
* ph - pipe handle pointer
* attrs - attributes of the request
* flags - usb_flags
*/
static int
{
uchar_t i;
/*
* Do some attributes validation checks here.
*/
for (i = 0; i < N_INVALID_FLAGS_ATTRS; i++) {
(usb_invalid_flags_attrs[i].ep_dir == X)) &&
(usb_invalid_flags_attrs[i].ep_attr == X)) &&
(usb_invalid_flags_attrs[i].usb_flags == X)) &&
(usb_invalid_flags_attrs[i].attrs == X))) {
"invalid (%d) : flags = 0x%x, attrs = 0x%x",
return (USB_INVALID_REQUEST);
}
}
return (USB_SUCCESS);
}
/*
* usba_rval2cr:
* convert rval to meaningful completion reason
* XXX extend completion reasons to get better mapping
*/
static struct {
int rval;
} rval2cr[] = {
{USB_SUCCESS, USB_CR_OK},
{0xffff, 0}
};
{
int i;
}
}
return (USB_CR_UNSPECIFIED_ERR);
}
/*
* usba_start_next_req:
* Arguments:
* ph_data - pointer to pipe handle
*
*/
void
{
int rval;
switch (ep_attrs) {
case USB_EP_ATTR_CONTROL:
case USB_EP_ATTR_BULK:
switch (usba_get_ph_state(ph_data)) {
case USB_PIPE_STATE_IDLE:
case USB_PIPE_STATE_CLOSING:
break;
default:
return;
}
break;
case USB_EP_ATTR_ISOCH:
case USB_EP_ATTR_INTR:
default:
return;
}
while ((wrp = (usba_req_wrapper_t *)
"usba_start_next_req: ph_data=0x%p state=%d",
if (ep_attrs == USB_EP_ATTR_CONTROL) {
}
"starting req = 0x%p",
(void *)USBA_WRP2CTRL_REQ(wrp));
switch (ep_attrs) {
case USB_EP_ATTR_CONTROL:
/* submit to hcd */
break;
case USB_EP_ATTR_BULK:
/* submit to hcd */
break;
default:
/* there shouldn't be any requests */
rval = USB_FAILURE;
break;
}
if (rval != USB_SUCCESS) {
}
/* we are done */
break;
} else {
switch (state) {
case USB_PIPE_STATE_CLOSING:
break;
case USB_PIPE_STATE_ERROR:
default:
break;
}
}
}
"usba_start_next_req done: ph_data=0x%p state=%d", (void *)ph_data,
}
/*
* usba_req_wrapper_alloc:
* Allocate + Initialize a usba_req_wrapper_t
*
* Arguments:
* dip - dev_info_t of the client driver
* req_len - sizeof request
* flags -
* USB_FLAGS_SLEEP - Sleep if resources are not available
* no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
*
* Return Values:
* pointer to usba_req_wrapper_t on success; NULL on failure.
*
*/
static usba_req_wrapper_t *
{
int kmflag;
return (NULL);
}
/* Allocate the usb_{c/b/i/i}_req + usba_req_wrapper_t structure */
/* initialize mutex for the queue */
&wrp->wr_allocated_list);
"usba_req_wrapper_alloc: wrp = 0x%p", (void *)wrp);
}
return (wrp);
}
/*
* usba_req_wrapper_free:
* Frees a usba_req_wrapper_t. Get rid of lists if any.
*
* Arguments:
* wrp: request wrapper structure
*/
void
{
"usba_req_wrapper_free: wrp=0x%p", (void *)wrp);
if (wrp) {
/* remove from queues */
if (ph_data) {
}
"usba_req_wrapper_free: data corruption");
}
}
}
/*
* usba_check_intr_context
* Set USB_CB_INTR_CONTEXT callback flag if executing in interrupt context
*/
{
if (servicing_interrupt() != 0) {
}
return (cb_flags);
}
/*
* usba_req_normal_cb:
* perform normal callback depending on request type
*/
void
{
"usba_req_normal_cb: "
"ph_data=0x%p state=%d wrp=0x%p ref=%d req=%d",
(pipe_state == USB_PIPE_STATE_CLOSING));
/* set done to indicate that we will do callback or cv_signal */
/* update the pipe state */
case USB_EP_ATTR_CONTROL:
case USB_EP_ATTR_BULK:
break;
case USB_EP_ATTR_INTR:
if ((direction == USB_EP_DIR_IN) &&
} else if ((direction == USB_EP_DIR_OUT) &&
(ph_data->p_req_count == 0)) {
}
break;
case USB_EP_ATTR_ISOCH:
if ((ph_data->p_req_count == 0) &&
(direction == USB_EP_DIR_OUT)) {
}
break;
}
/* now complete the request */
} else {
/* This sets USB_CB_INTR_CONTEXT as needed. */
case USB_EP_ATTR_CONTROL:
break;
case USB_EP_ATTR_INTR:
break;
case USB_EP_ATTR_BULK:
break;
case USB_EP_ATTR_ISOCH:
break;
}
}
/* we are done with this request */
ph_data->p_req_count--;
}
/*
* usba_req_exc_cb:
* perform exception cb depending on request type.
* ensure the completion reason is non zero
*/
void
{
"usba_req_exc_cb: %s%d: ph_data=0x%p (ep%x) state=%d wrp=0x%p "
"ref=%d reqcnt=%d cr=%d",
/* if there was no CR set already, set it now */
}
case USB_EP_ATTR_CONTROL:
if (USBA_WRP2CTRL_REQ(req_wrp)->
}
break;
case USB_EP_ATTR_INTR:
if (USBA_WRP2INTR_REQ(req_wrp)->
}
break;
case USB_EP_ATTR_BULK:
if (USBA_WRP2BULK_REQ(req_wrp)->
}
break;
case USB_EP_ATTR_ISOCH:
if (USBA_WRP2ISOC_REQ(req_wrp)->
}
break;
}
}
} else {
case USB_EP_ATTR_CONTROL:
if (ph_data->p_active_cntrl_req_wrp ==
(usb_opaque_t)req_wrp) {
}
break;
case USB_EP_ATTR_INTR:
break;
case USB_EP_ATTR_BULK:
break;
case USB_EP_ATTR_ISOCH:
break;
}
}
/* we are done with this request */
ph_data->p_req_count--;
}
/*
* usba_do_req_exc_cb:
* called when flushing requests. rather than calling usba_req_exc_cb()
* directly, this function uses usba_hcdi_cb() which ensures callback
* order is preserved
*/
void
{
}
/*
* usba_req_set_cb_flags:
* This function sets the request's callback flags to those stored in the
* request wrapper ORed with those received as an argument. Additionally
* USB_CB_INTR_CONTEXT is set if called from interrupt context.
*
* NOTE: The xfer may have succeeded, which client driver can determine
* by looking at usb_cr_t
*/
void
{
"usba_req_set_cb_flags: wrp=0x%p cb-flags=0x%x",
/* do the callback under taskq context */
case USB_EP_ATTR_CONTROL:
break;
case USB_EP_ATTR_INTR:
break;
case USB_EP_ATTR_BULK:
break;
case USB_EP_ATTR_ISOCH:
break;
}
}
/*
* usba_pipe_sync_wait:
* wait for the request to finish.
* usba_hcdi_cb() does a cv_signal thru a soft intr
*
* Arguments:
* ph_data - pointer to pipe handle data
* wrp - pointer to usba_req_wrapper_structure.
*
* Return Values:
* USB_SUCCESS - request successfully executed
* USB_FAILURE - request failed
*/
static int
{
}
"usba_pipe_sync_wait: ph_data=0x%p cr=0x%x", (void *)ph_data,
/* XXX return something better than USB_FAILURE?? */
}
/*
* Allocate usb control request and a USB request wrapper
*
* Arguments:
* dip - dev_info_t of the client driver
* len - length of "data" for this control request
* flags:
* USB_FLAGS_SLEEP - Sleep if resources are not available
* no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
*
* Return Values: usb_ctrl_req_t on success, NULL on failure
*/
{
"usb_alloc_ctrl_req: dip=0x%p, wlen=0x%lx, flags=0x%x",
/* Allocate + Initialize the usba_req_wrapper_t structure */
if (dip &&
NULL)) {
/* Allocate the usb_ctrl_req data mblk */
if (len) {
if (flags & USB_FLAGS_SLEEP) {
}
}
}
"usb_alloc_ctrl_req: ctrl_req = 0x%p", (void *)ctrl_req);
return (ctrl_req);
}
/*
* usb_free_ctrl_req:
* free USB control request + wrapper
*
* Arguments:
* req - pointer to usb_ctrl_req_t
*/
void
{
if (req) {
"usb_free_ctrl_req: req = 0x%p", (void *)req);
}
}
}
/*
* Client driver calls this function to issue the control
* request to the USBA
*
* Arguments:
* pipe_handle: control pipe pipehandle (obtained via usb_pipe_open()
* req: control request
* usb_flags:
* USB_FLAGS_SLEEP - wait for the request to complete
*
* Return Values:
* USB_SUCCESS - request successfully executed
* USB_FAILURE - request failed
*/
int
{
int rval;
"usb_pipe_ctrl_xfer: req=0x%p, wrp=0x%p\n\t"
"setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf=0x%x",
return (USB_INVALID_PIPE);
}
USB_EP_ATTR_CONTROL)) != USB_SUCCESS) {
"request rejected: rval=%d", rval);
return (rval);
}
/* we accepted the request, so increment the req count */
ph_data->p_req_count++;
/* Get the current bulk pipe state */
/*
* if this is for the default pipe, and the pipe is in error,
* just queue the request. autoclearing will start this request
*
* if there is already an active request in the queue
* then just add this request to the queue.
*/
switch (pipe_state) {
case USB_PIPE_STATE_IDLE:
"usb_pipe_ctrl_xfer: queue request 0x%p",
(void *)req);
rval = USB_SUCCESS;
} else {
/* issue the request to HCD */
}
break;
case USB_PIPE_STATE_ACTIVE:
"usb_pipe_ctrl_xfer: queue request 0x%p", (void *)req);
rval = USB_SUCCESS;
break;
case USB_PIPE_STATE_ERROR:
if (USBA_IS_DEFAULT_PIPE(ph_data)) {
"usb_pipe_ctrl_xfer: queue request 0x%p on "
"pending def pipe error", (void *)req);
rval = USB_SUCCESS;
} else {
"usb_pipe_ctrl_xfer: pipe is in error state ");
}
break;
default:
"usb_pipe_ctrl_xfer: pipe state %d", pipe_state);
break;
}
/* if there has been a failure, decrement req count */
if (rval != USB_SUCCESS) {
"usb_pipe_ctrl_xfer: hcd failed req 0x%p", (void *)req);
}
ph_data->p_req_count--;
if ((ph_data->p_req_count == 0) &&
}
/* if success and sleep specified, wait for completion */
} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
}
"usb_pipe_ctrl_xfer: rval=0x%x", rval);
return (rval);
}
/*
* usb_pipe_sync_ctrl_xfer():
* for simple synchronous control transactions this wrapper function
* will perform the allocation, xfer, and deallocation
* USB_ATTRS_AUTOCLEARING will be enabled
*
* Arguments:
* dip - pointer to clients devinfo
* pipe_handle - control pipe pipehandle (obtained via usb_pipe_open()
* bmRequestType - characteristics of request
* bRequest - specific request
* wValue - varies according to request
* wIndex - index or offset
* wLength - number of bytes to xfer
* data - pointer to pointer to data and may be NULL if
* wLength is 0
* attrs - required request attributes
* completion_reason - completion status
* cb_flags - request completions flags
* flags - none
*
* Return Values:
* USB_SUCCESS - request successfully executed
* USB_* - request failed
*
* Notes:
* - in the case of failure, the client should check completion_reason and
* and cb_flags and determine further recovery action
* - the client should check data and if non-zero, free the data on
* completion
*/
int
{
int rval;
#ifdef DEBUG
#endif
"usb_pipe_sync_ctrl_xfer: ph=0x%p\n\t"
"setup = 0x%x 0x%x 0x%x 0x%x 0x%x uf = 0x%x", (void *)pipe_handle,
goto done;
}
if (servicing_interrupt()) {
goto done;
}
goto done;
}
/* Initialize the ctrl_req structure */
/* Issue control xfer to the HCD */
flags | USB_FLAGS_SLEEP);
#ifdef DEBUG
"req=0x%p, cr=%s cb_flags=%s data=0x%p rval=%s",
#endif
/* copy back ctrl_req values */
if (data) {
}
if (completion_reason) {
}
if (cb_flags) {
}
/* Free up the control request now */
done:
#ifdef DEBUG
#endif
if (ph_data) {
}
return (rval);
}
/*
* usb_pipe_ctrl_xfer_wait():
* Easy-to-use wrapper around usb_pipe_sync_ctrl_xfer.
*
* ARGUMENTS:
* pipe_handle - control pipe pipehandle (obtained via usb_pipe_open())
* setup - setup descriptor params, attributes
* data - pointer to pointer to data and may be NULL when
* wLength is 0
* completion_reason - completion status.
* cb_flags - request completions flags.
* flags - none.
*
* RETURN VALUES:
* USB_SUCCESS - request successfully executed.
* USB_* - failure
*/
int
{
return (usb_pipe_sync_ctrl_xfer(
data,
flags));
}
/*
* usb_alloc_bulk_req:
* Allocate a usb bulk request + usba_req_wrapper_t
*
* Arguments:
* dip - dev_info_t of the client driver
* len - length of "data" for this bulk request
* flags:
* USB_FLAGS_SLEEP - Sleep if resources are not available
*
* Return Values:
* usb_bulk_req_t on success, NULL on failure
*/
{
"usb_alloc_bulk_req: dip=0x%p wlen=0x%lx flags=0x%x",
/* Allocate + Initialize the usba_req_wrapper_t structure */
if (dip &&
NULL)) {
/* Allocate the usb_bulk_req data mblk */
if (len) {
if (flags & USB_FLAGS_SLEEP) {
}
}
}
"usb_alloc_bulk_req: bulk_req = 0x%p", (void *)bulk_req);
return (bulk_req);
}
/*
* usb_free_bulk_req:
* free USB bulk request + wrapper
*
* Arguments:
* req - pointer to usb_bulk_req_t
*/
void
{
if (req) {
"usb_free_bulk_req: req=0x%p", (void *)req);
}
}
}
/*
* Client driver calls this function to issue the bulk xfer to the USBA
*
* Arguments:-
* pipe_handle - bulk pipe handle (obtained via usb_pipe_open()
* req - bulk data xfer request (IN or OUT)
* usb_flags - USB_FLAGS_SLEEP - wait for the request to complete
*
* Return Values:
* USB_SUCCESS - success
* USB_FAILURE - unspecified failure
*/
int
{
int rval;
return (USB_INVALID_PIPE);
}
USB_EP_ATTR_BULK)) != USB_SUCCESS) {
return (rval);
}
/* we accepted the request */
ph_data->p_req_count++;
/* Get the current bulk pipe state */
/*
* if there is already an active request in the queue
* then just add this request to the queue.
*/
switch (pipe_state) {
case USB_PIPE_STATE_IDLE:
"usb_pipe_bulk_xfer: queue request 0x%p",
(void *)req);
rval = USB_SUCCESS;
} else {
/* issue the request to HCD */
}
break;
case USB_PIPE_STATE_ACTIVE:
"usb_pipe_bulk_xfer: queue request 0x%p", (void *)req);
rval = USB_SUCCESS;
break;
default:
"usb_pipe_bulk_xfer: pipe state %d", pipe_state);
break;
}
if (rval != USB_SUCCESS) {
}
ph_data->p_req_count--;
if ((ph_data->p_req_count == 0) &&
}
} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
}
"usb_pipe_bulk_xfer: rval=%d", rval);
return (rval);
}
/*
* usb_pipe_bulk_transfer_size:
* - request HCD to return bulk max transfer data size
*
* Arguments:
* dip - pointer to dev_info_t
* size - pointer to bulk_transfer_size
*
* Return Values:
* USB_SUCCESS - request successfully executed
* USB_FAILURE - request failed
*/
int
{
}
int
{
return (USB_INVALID_ARGS);
}
"usb_pipe_bulk_transfer_size: usba_device=0x%p",
(void *)usba_device);
if ((usba_device) &&
return (usba_device->usb_hcdi_ops->
} else {
*size = 0;
return (USB_FAILURE);
}
}
/*
* usb_alloc_intr_req:
* Allocate usb interrupt request
*
* Arguments:
* dip - dev_info_t of the client driver
* len - length of "data" for this interrupt request
* flags -
* USB_FLAGS_SLEEP - Sleep if resources are not available
*
* Return Values:
* usb_intr_req_t on success, NULL on failure
*/
{
"usb_alloc_intr_req: dip=0x%p, len=0x%lx, flags=0x%x",
/* Allocate + Initialize the usba_req_wrapper_t structure */
if ((dip &&
NULL)) {
/* Allocate the usb_intr_req data mblk */
if (len) {
if (flags & USB_FLAGS_SLEEP) {
}
}
}
"usb_alloc_intr_req: intr_req=0x%p", (void *)intr_req);
return (intr_req);
}
/*
* usba_hcdi_dup_intr_req:
* create duplicate of interrupt request
*
* Arguments:
* dip - devinfo pointer
* reqp - original requestp pointer
* len - length of "data" for this interrupt request
* flags -
* USB_FLAGS_SLEEP - Sleep if resources are not available
*
* Return Values:
* usb_intr_req_t on success, NULL on failure
*/
{
return (NULL);
}
}
return (intr_reqp);
}
/*
* usb_free_intr_req:
* free USB intr request + wrapper
*
* Arguments:
* req - pointer to usb_intr_req_t
*/
void
{
if (req) {
"usb_free_intr_req: req = 0x%p", (void *)req);
}
}
}
/*
* Client driver calls this function to issue the intr xfer to the USBA
*
* Arguments:-
* pipe_handle - intr pipe handle (obtained via usb_pipe_open()
* req - intr data xfer request (IN or OUT)
* flags -
* USB_FLAGS_SLEEP - wait for the request to complete
* Return Values
* USB_SUCCESS - success
* USB_FAILURE - unspecified failure
*/
int
{
int rval;
"usb_pipe_intr_req: req=0x%p uf=0x%x",
return (USB_INVALID_PIPE);
}
USB_EP_ATTR_INTR)) != USB_SUCCESS) {
return (rval);
}
/* Get the current interrupt pipe state */
switch (pipe_state) {
case USB_PIPE_STATE_IDLE:
/*
* if the pipe state is in middle of transition,
* i.e. stop polling is in progress, fail any
* attempt to do a start polling
*/
if (ph_impl->usba_ph_state_changing > 0) {
"usb_pipe_intr_req: fail request - "
"stop polling in progress");
return (USB_FAILURE);
} else {
}
break;
case USB_PIPE_STATE_ACTIVE:
/*
* If this is interrupt IN pipe and if we are
* already polling, return failure.
*/
if (direction == USB_EP_DIR_IN) {
"usb_pipe_intr_req: already polling");
return (USB_FAILURE);
}
break;
default:
"usb_pipe_intr_req: pipe state %d", pipe_state);
return (USB_PIPE_ERROR);
}
/* we accept the request */
ph_data->p_req_count++;
/* issue the request out */
/* the request failed, decrement the ref_count */
}
ph_data->p_req_count--;
if ((ph_data->p_req_count == 0) &&
}
/* if sleep specified, wait for completion */
} else if (wrp_usb_flags & USBA_WRP_FLAGS_WAIT) {
}
"usb_pipe_intr_req: rval=0x%x", rval);
return (rval);
}
/*
* usba_pipe_sync_stop_intr_polling:
* - set up for sync transport, if necessary
* - request HCD to stop polling
* - wait for draining of all callbacks
*/
/*ARGSUSED*/
static int
{
int rval;
"usba_pipe_sync_stop_intr_polling: flags=0x%x", flags);
"usba_pipe_sync_stop_intr_polling: pipe closed");
return (USB_INVALID_PIPE);
}
"usba_pipe_sync_stop_intr_polling: pipe error");
return (USB_PIPE_ERROR);
}
"usba_pipe_sync_stop_intr_polling: already idle");
return (USB_SUCCESS);
}
flags |= USB_FLAGS_SLEEP;
for (;;) {
/*
* The host controller has stopped polling of the endpoint.
* Now, drain the callbacks if there are any on the callback
* queue.
*/
if (rval == USB_SUCCESS) {
/*
* there is a tiny window that the client driver
* may still have restarted the polling and we
* have to let the stop polling win)
*/
if (rval != USB_SUCCESS) {
continue;
}
}
break;
}
"usba_pipe_sync_stop_intr_polling: rval=0x%x", rval);
return (rval);
}
/*
* dummy callback function for stop polling
*/
static void
int rval,
{
"usba_dummy_callback: "
"ph=0x%p rval=0x%x flags=0x%x cb_arg=0x%p",
}
/*
* usb_pipe_stop_intr_polling:
* stop polling for interrupt pipe IN data
* The HCD doesn't do a usba_hcdi_cb().
* Arguments:
* pipe_handle - pipe handle
* flags -
* USB_FLAGS_SLEEP: wait for completion
*/
void
{
"usba_pipe_stop_intr_polling: flags=0x%x", flags);
"usba_pipe_stop_intr_polling: pipe closed");
return;
}
USB_EP_ATTR_MASK) != USB_EP_ATTR_INTR) {
"usba_pipe_stop_intr_polling: wrong pipe type");
return;
}
"usba_pipe_stop_intr_polling: wrong pipe direction");
return;
}
"usba_pipe_stop_intr_polling: invalid context");
return;
}
}
/*
* usb_alloc_isoc_req:
* - Allocate usb isochronous resources that includes usb isochronous
* request and array of packet descriptor structures and wrapper.
*
* Arguments:
* dip - dev_info_t of the client driver
* isoc_pkts_count - number of isoc_pkt_descr_t's
* len - length of "data" for this isochronous request
* flags -
* USB_FLAGS_SLEEP - Sleep if resources are not available
* no USB_FLAGS_SLEEP - Don't Sleep if resources are not available
*
* Return Values:
* usb_isoc_req_t on success, NULL on failure
*/
/*ARGSUSED*/
{
(sizeof (usb_isoc_pkt_descr_t) * isoc_pkts_count);
"usb_alloc_isoc_req: dip=0x%p pkt_cnt=%d len=%lu flags=0x%x",
/* client needs to set isoc_pks_count */
if (dip && isoc_pkts_count) {
/* Allocate + Initialize the usba_req_wrapper_t structure */
NULL) {
/* Allocate the usb_isoc_req data mblk */
if (len) {
}
}
}
}
if (isoc_req) {
/* Initialize all the fields of usb isochronous request */
}
"usb_alloc_isoc_req: isoc_req = 0x%p", (void *)isoc_req);
return (isoc_req);
}
/*
* usba_hcdi_dup_isoc_req:
* create duplicate of isoc request
*
* Arguments:
* dip - devinfo pointer
* reqp - original request pointer
* len - length of "data" for this isoc request
* flags -
* USB_FLAGS_SLEEP - Sleep if resources are not available
*
* Return Values:
* usb_isoc_req_t on success, NULL on failure
*/
{
return (isoc_reqp);
}
/* calculate total data length required in original request */
}
}
}
return (isoc_reqp);
}
/*
* usb_free_isoc_req:
* - Deallocate usb isochronous resources that includes usb isochronous
* request and array of packet descriptor strcutures.
*
* Arguments:
* req - pointer to usb_isoc_req_t
*/
void
{
if (req) {
"usb_free_isoc_req: req=0x%p", (void *)req);
}
}
}
/*
* usb_get_current_frame_number:
* - request HCD to return current usb frame number
*
* Arguments:
* dip - pointer to dev_info_t
*
* Return Values:
* current_frame_number - request successfully executed
* 0 - request failed
*/
{
"usb_get_current_frame_number: dip=0x%p", (void *)dip);
if (dip) {
if (usba_device->usb_hcdi_ops->
if (usba_device->usb_hcdi_ops->
&frame_number) == USB_SUCCESS) {
return (frame_number);
}
}
}
return (0);
}
/*
* usb_get_max_isoc_pkts:
* - request HCD to return maximum isochronous packets per request
*
* Arguments:
* dip - pointer to dev_info_t
*
* Return Values:
* isoc_pkt - request successfully executed
* 0 - request failed
*/
{
return (usb_get_max_pkts_per_isoc_request(dip));
}
{
if (dip) {
"usb_get_max_isoc_pkts: usba_device=0x%p",
(void *)usba_device);
if (usba_device->usb_hcdi_ops->
&max_isoc_pkts_per_request) == USB_SUCCESS) {
return (max_isoc_pkts_per_request);
}
}
}
return (0);
}
/*
* usb_pipe_isoc_xfer:
* - check for pipe stalled
* - request HCD to transport isoc data asynchronously
*
* Arguments:
* pipe_handle - isoc pipe pipehandle (obtained via usb_pipe_open())
* req - isochronous request
*
* Return Values:
* USB_SUCCESS - request successfully executed
* USB_FAILURE - request failed
*/
int
{
int rval;
"usb_pipe_isoc_xfer: flags=0x%x", flags);
return (USB_INVALID_PIPE);
}
USB_EP_ATTR_ISOCH)) != USB_SUCCESS) {
return (rval);
}
req->isoc_error_count = 0;
/* Get the current isoch pipe state */
switch (pipe_state) {
case USB_PIPE_STATE_IDLE:
break;
case USB_PIPE_STATE_ACTIVE:
if (direction == USB_EP_DIR_IN) {
"usb_pipe_isoc_req: already polling");
return (USB_FAILURE);
}
break;
default:
"usb_pipe_isoc_req: pipe state %d", pipe_state);
return (USB_PIPE_ERROR);
}
/* we accept the request */
ph_data->p_req_count++;
}
ph_data->p_req_count--;
if ((ph_data->p_req_count == 0) &&
}
}
"usb_pipe_isoc_req: rval=%x", rval);
return (rval);
}
/*
* usba_pipe_sync_stop_isoc_polling:
* - set up for sync transport, if necessary
* - request HCD to stop polling
* - wait for draining of all callbacks
*
* Arguments:
* dip - dev_info pointer
* pipe_handle - pointer to pipe handle
* flags - USB_FLAGS_SLEEP: wait for completion
*/
/*ARGSUSED*/
static int
{
int rval;
"usba_pipe_sync_stop_isoc_polling: uf=0x%x", flags);
"usba_pipe_stop_isoc_polling: pipe closed");
return (USB_INVALID_PIPE);
}
"usba_pipe_sync_stop_isoc_polling: pipe error");
return (USB_PIPE_ERROR);
}
"usba_pipe_sync_stop_isoc_polling: already stopped");
return (USB_SUCCESS);
}
flags |= USB_FLAGS_SLEEP;
for (;;) {
/*
* The host controller has stopped polling of the endpoint.
* Now, drain the callbacks if there are any on the callback
* queue.
*/
if (rval == USB_SUCCESS) {
/*
* there is a tiny window that the client driver
* may still have restarted the polling and we
* let the stop polling win
*/
if (rval != USB_SUCCESS) {
continue;
}
}
break;
}
"usba_pipe_sync_stop_isoc_polling: rval=0x%x", rval);
return (rval);
}
/*
* usb_pipe_stop_isoc_polling:
* stop polling for isoc IN data
*
* Arguments:
* pipe_handle - pipe handle
* flags -
* USB_FLAGS_SLEEP: wait for completion
*/
void
{
"usba_pipe_stop_isoc_polling: uf=0x%x", flags);
"usba_pipe_stop_isoc_polling: pipe closed");
return;
}
"usba_pipe_stop_isoc_polling: wrong pipe type");
return;
}
"usba_pipe_stop_isoc_polling: wrong pipe direction");
return;
}
"usba_pipe_stop_intr_polling: invalid context");
return;
}
}