usba_impl.h revision ff0e937b36dcde1a47ff7b00aa76a491c0dc07a8
/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_USB_USBA_USBA_IMPL_H
#define _SYS_USB_USBA_USBA_IMPL_H
#include <sys/usb/usba.h>
#include <sys/usb/usba/hcdi.h>
#include <sys/usb/usba/hubdi.h>
#include <sys/usb/usba/usba_private.h>
#include <sys/usb/usba/usba_types.h>
#include <sys/taskq.h>
#include <sys/disp.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* UGEN binding values specified in <hcd>.conf files
*/
#define USBA_UGEN_DEVICE_BINDING 1
#define USBA_UGEN_INTERFACE_BINDING 2
#define USBA_UGEN_INTERFACE_ASSOCIATION_BINDING 3
/*
* Allocating a USB address
*/
#define USBA_MAX_ADDRESS 127
#define USBA_ADDRESS_ARRAY_SIZE ((USBA_MAX_ADDRESS+8)/8)
/*
* async execution of usb_pipe_* functions which have a
* completion callback parameter (eg. usb_pipe_close(),
* usb_pipe_reset(), usb_pipe_stop_*_polling()
*/
typedef struct usba_pipe_async_req {
dev_info_t *dip;
struct usba_ph_impl *ph_impl;
usb_opaque_t arg;
usb_flags_t usb_flags;
void (*callback)(
usb_pipe_handle_t ph,
usb_opaque_t callback_arg,
int rval,
usb_cb_flags_t error_code);
usb_opaque_t callback_arg;
int (*sync_func)(dev_info_t *,
usba_ph_impl_t *,
struct usba_pipe_async_req *,
usb_flags_t);
} usba_pipe_async_req_t;
_NOTE(SCHEME_PROTECTS_DATA("unique per call", usba_pipe_async_req_t))
/* per-pipe taskq */
int usba_async_ph_req(usba_pipe_handle_data_t *, void (*func)(void *),
void *, usb_flags_t);
/*
* usb wrapper around pm_request_power_change to allow for
* non blocking behavior
*/
typedef struct usba_pm_req {
dev_info_t *dip;
int comp;
int old_level;
int level;
void (*cb)(void *, int);
void *arg;
uint_t flags;
} usba_pm_req_t;
_NOTE(SCHEME_PROTECTS_DATA("unique per call", usba_pm_req_t))
/*
* Request wrappers for control/bulk/interrupt and isoch pipes
* These are hidden from client driver. They serve as place-holders
* for doing callbacks
*
* Request allocation: wrapper + usb_*_req_t alloc'ed together:
*
* +-----------------------+
* | wr_queue | for callbacks
* +-----------------------+
* | wr_req |-------+ wr_req points to
* +-----------------------+ | the req below.
* | | |
* | .... | |
* | req_wrapper_t | |
* | | |
* +-----------------------+<------+
* | |
* | .... |
* | ctrl/bulk/intr/isoch |
* | req_t |
* | |
* | |
* +-----------------------+
*/
typedef struct usba_req_wrapper {
/* queueing in either a request or callback queue */
usba_list_entry_t wr_queue;
/*
* The request could be control/bulk/intr/isoc
* See usbai.h usb_ctrl_req_t/usb_bulk_req_t
* usb_intr_req_t/usb_isoc_req_t
*/
usb_opaque_t wr_req;
/* for allocation tracking in usba_device_t */
usba_list_entry_t wr_allocated_list;
/*
* All reqs that are synchronous sleep on this cv
* for completion notification.
* In hcdi soft interrupt handler we call cv_signal()
*/
kcondvar_t wr_cv;
/*
* This goes hand-in-hand with wr_cv. It is set by the soft intr hdlr
* before doing a cv_signal
*/
boolean_t wr_done;
dev_info_t *wr_dip; /* owner */
usb_opaque_t wr_hcd_private; /* for HCD's use */
usba_pipe_handle_data_t *wr_ph_data; /* ptr to pipe handle */
usb_cr_t wr_cr; /* save cr from HCDI */
usb_cb_flags_t wr_cb_flags; /* save cb_flags */
usb_flags_t wr_usb_flags; /* save usb flags from HCDI */
usb_req_attrs_t wr_attrs; /* save attrs from HCDI */
/* total lenght of wrapper and request */
size_t wr_length;
} usba_req_wrapper_t;
_NOTE(SCHEME_PROTECTS_DATA("method", usba_req_wrapper))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_ctrl_req))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_bulk_req))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_intr_req))
_NOTE(SCHEME_PROTECTS_DATA("method", usb_isoc_req))
/* additional flag for wr_usb_flags */
#define USBA_WRP_FLAGS_WAIT 0x01
/* additional usb flags, not exposed to clients */
#define USBA_FLAGS_PRIVILEGED 0x02 /* for default pipe operations */
/* Macros to convert wrapper to different request and vice-versa */
/* to get the wr->wr_req field */
#define USBA_WRP2REQ(wrp) ((wrp)->wr_req)
/* to get the wrapper form the wr_req field */
#define USBA_REQ2WRP(req) (usba_req_wrapper_t *)\
((uintptr_t)(req) - sizeof (usba_req_wrapper_t))
/* to set the the address in the wr_req field */
#define USBA_SETREQ_ADDR(wrp) ((uintptr_t)(wrp) + sizeof (*(wrp)))
/* to get the 4 xfer type requests */
#define USBA_WRP2CTRL_REQ(wrp) ((usb_ctrl_req_t *)USBA_WRP2REQ((wrp)))
#define USBA_WRP2INTR_REQ(wrp) ((usb_intr_req_t *)USBA_WRP2REQ((wrp)))
#define USBA_WRP2BULK_REQ(wrp) ((usb_bulk_req_t *)USBA_WRP2REQ((wrp)))
#define USBA_WRP2ISOC_REQ(wrp) ((usb_isoc_req_t *)USBA_WRP2REQ((wrp)))
/* to get pipe_handle from the wrapper */
#define USBA_WRP2PH_DATA(wrp) \
(usba_pipe_handle_data_t *)((wrp)->wr_ph_data)
/* to get to the wr_queue from the wrapper */
#define USBA_WRQUEUE2WRP(queue) (usba_req_wrapper_t *)(queue)
/* to get to the wr_allocated queue from the wrapper */
#define USBA_ALLOCQ2WRP(queue) (usba_req_wrapper_t *)((uintptr_t) \
(queue) - sizeof (usba_list_entry_t) - sizeof (usb_opaque_t))
/* alias for pipe handle member p_usba_private */
#define p_active_cntrl_req_wrp p_usba_private
/*
* This function is used to get the HCD private field maintained by USBA.
* HCD calls this function.
*/
usb_opaque_t usba_hcdi_get_ctrl_req_hcd_private(usb_ctrl_req_t *);
/*
* This function is used to set the HCD private field maintained by USBA.
* HCD calls this function.
*/
void usba_hcdi_set_ctrl_req_hcd_private(usb_ctrl_req_t *, usb_opaque_t);
int usba_set_usb_address(usba_device_t *);
void usba_unset_usb_address(usba_device_t *);
/*
* Per Hub Data Structures
*/
typedef struct usba_hubdi {
usba_list_entry_t hubdi_list; /* linking in hubdi list */
dev_info_t *hubdi_dip; /* ptr to devinfo struct */
int hubdi_flags; /* flag options */
} usba_hubdi_t;
/*
* usba_get_mfg_prod_sn_str:
* Return a string containing mfg, product, serial number strings.
* Remove duplicates if some strings are the same.
*/
char *usba_get_mfg_prod_sn_str(dev_info_t *, char *, int);
/* return value when user doesn't specify configuration index */
#define USBA_DEV_CONFIG_INDEX_UNDEFINED -1
/*
* prototypes
*/
void usba_usba_initialization();
void usba_usba_destroy();
void usba_usbai_register_initialization();
void usba_usbai_register_destroy();
void usba_usbai_initialization();
void usba_usbai_destroy();
void usba_hubdi_initialization();
void usba_hubdi_destroy();
void usba_devdb_initialization();
void usba_devdb_destroy();
int usba_hubdi_register(dev_info_t *, uint_t);
int usba_hubdi_unregister(dev_info_t *);
void usba_whcdi_initialization();
void usba_whcdi_destroy();
int usba_is_root_hub(dev_info_t *dip);
int usba_is_wa(dev_info_t *dip);
int usba_is_hwa(dev_info_t *dip);
usba_device_t *usba_alloc_usba_device(dev_info_t *);
void usba_free_wireless_data(usba_wireless_data_t *wireless_data);
void usba_free_usba_device(usba_device_t *usba_device_t);
void usba_clear_data_toggle(usba_device_t *usba_device);
void usba_start_next_req(usba_pipe_handle_data_t *ph);
int usba_pipe_check_handle(usba_pipe_handle_data_t *);
int usba_drain_cbs(usba_pipe_handle_data_t *, usb_cb_flags_t,
usb_cr_t);
int usba_pipe_setup_func_call(dev_info_t *,
int (*sync_func)(dev_info_t *,
usba_ph_impl_t *, usba_pipe_async_req_t *,
usb_flags_t),
usba_ph_impl_t *,
usb_opaque_t,
usb_flags_t,
void (*cb)(usb_pipe_handle_t, usb_opaque_t,
int, usb_cb_flags_t),
usb_opaque_t);
void usba_pipe_new_state(usba_pipe_handle_data_t *, usb_pipe_state_t);
void usba_add_root_hub(dev_info_t *dip);
void usba_rem_root_hub(dev_info_t *dip);
/*
* retrieve string descriptors for manufacturer, vendor and serial
* number
*/
void usba_get_dev_string_descrs(dev_info_t *, usba_device_t *);
/*
* Check if we are not in interrupt context and have
* USB_FLAGS_SLEEP flags set.
*/
#define USBA_CHECK_CONTEXT() ASSERT(!(servicing_interrupt()))
/*
* USBA module Masks
*/
#define DPRINT_MASK_USBA 0x00000001
#define DPRINT_MASK_USBAI 0x00000002
#define DPRINT_MASK_HUBDI 0x00000004
#define DPRINT_MASK_HCDI 0x00000008
#define DPRINT_MASK_HCDI_DUMPING 0x00000010
#define DPRINT_MASK_HUBDI_DUMPING 0x00000020
#define DPRINT_MASK_REGISTER 0x00000040
#define DPRINT_MASK_DEVDB 0x00000080
#define DPRINT_MASK_WHCDI 0x00000100
#define DPRINT_MASK_ALL 0xFFFFFFFF
typedef struct usba_log_handle_impl {
dev_info_t *lh_dip;
char *lh_name;
uint_t *lh_errlevel;
uint_t *lh_mask;
uint_t *lh_instance_filter;
uint_t lh_flags;
} usba_log_handle_impl_t;
_NOTE(SCHEME_PROTECTS_DATA("USBA managed data", usba_log_handle_impl))
/*
* Miscellaneous definitions.
*/
/* possible strlen of a USB driver's name */
#define USBA_DRVNAME_LEN 40
/* strings passed to usb_dprintfN() are this long */
#define USBA_PRINT_BUF_LEN 256
/*
* usba_set_node_name() sets a device info node name
* according to class, subclass, and protocol.
* a subclass == -1 or protocol == -1 is considered a "don't care".
*/
#define DONTCARE ((int16_t)-1)
#define FLAG_INTERFACE_NODE 0
#define FLAG_DEVICE_NODE 1
#define FLAG_COMBINED_NODE 2
#define FLAG_INTERFACE_ASSOCIATION_NODE 3
typedef struct node_name_entry {
int16_t class;
int16_t subclass;
int16_t protocol;
char *name;
} node_name_entry_t;
/*
* USB enumeration statistics support
*/
/* Flags telling which stats usba_update_hotplug_stats should update */
#define USBA_TOTAL_HOTPLUG_SUCCESS 0x01
#define USBA_HOTPLUG_SUCCESS 0x02
#define USBA_TOTAL_HOTPLUG_FAILURE 0x04
#define USBA_HOTPLUG_FAILURE 0x08
/*
* Increment enumeration stats indicated by the flags
*/
void usba_update_hotplug_stats(dev_info_t *, usb_flags_t);
/* Retrieve the current enumeration hotplug statistics */
void usba_get_hotplug_stats(dev_info_t *,
ulong_t *, ulong_t *, ulong_t *,
ulong_t *, uchar_t *);
/* Reset the resetable hotplug stats */
void usba_reset_hotplug_stats(dev_info_t *);
extern usb_log_handle_t usbai_log_handle;
extern kmutex_t usbai_mutex;
void usba_req_normal_cb(usba_req_wrapper_t *);
void usba_req_exc_cb(usba_req_wrapper_t *, usb_cr_t, usb_cb_flags_t);
void usba_do_req_exc_cb(usba_req_wrapper_t *, usb_cr_t,
usb_cb_flags_t);
void usba_req_set_cb_flags(usba_req_wrapper_t *, usb_cb_flags_t);
/*
* Creating/Destroying children (root hub, and hub children)
*/
int usba_create_child_devi(dev_info_t *, char *, usba_hcdi_ops_t *,
dev_info_t *, usb_port_status_t,
usba_device_t *, dev_info_t **);
int usba_destroy_child_devi(dev_info_t *, uint_t);
/* utility function to map rval to a meaningful cr */
usb_cr_t usba_rval2cr(int);
/* various conversion functions */
usb_pipe_handle_t usba_get_dflt_pipe_handle(dev_info_t *);
dev_info_t *usba_get_dip(usb_pipe_handle_t);
usb_pipe_handle_t usba_usbdev_to_dflt_pipe_handle(usba_device_t *);
usb_pipe_handle_t usba_get_pipe_handle(usba_pipe_handle_data_t *);
usba_pipe_handle_data_t *usba_get_ph_data(usb_pipe_handle_t);
usb_pipe_state_t usba_get_ph_state(usba_pipe_handle_data_t *);
int usba_get_ph_ref_count(usba_pipe_handle_data_t *);
/* increment and decrement ref_count */
usba_pipe_handle_data_t *usba_hold_ph_data(usb_pipe_handle_t);
void usba_release_ph_data(usba_ph_impl_t *);
/* close all pipe and mark them persistent */
void usba_persistent_pipe_close(usba_device_t *);
/* reopen pipes that are marked persistent */
int usba_persistent_pipe_open(usba_device_t *);
/* check for leaks in hubd and usb_mid */
void usba_check_for_leaks(usba_device_t *);
/* free request wrappers */
void usba_req_wrapper_free(usba_req_wrapper_t *);
#ifdef __cplusplus
}
#endif
#endif /* _SYS_USB_USBA_USBA_IMPL_H */