#include <sys/usb/hcd/xhci/xhci.h>
#pragma pack(1)
typedef struct xhci_dev_conf {
uint8_t xdc_cfg_bLength;
uint8_t xdc_cfg_bDescriptorType;
uint16_t xdc_cfg_wTotalLength;
uint8_t xdc_cfg_bNumInterfaces;
uint8_t xdc_cfg_bConfigurationValue;
uint8_t xdc_cfg_iConfiguration;
uint8_t xdc_cfg_bmAttributes;
uint8_t xdc_cfg_bMaxPower;
uint8_t xdc_if_bLength;
uint8_t xdc_if_bDescriptorType;
uint8_t xdc_if_bInterfaceNumber;
uint8_t xdc_if_bAlternateSetting;
uint8_t xdc_if_bNumEndpoints;
uint8_t xdc_if_bInterfaceClass;
uint8_t xdc_if_bInterfaceSubClass;
uint8_t xdc_if_bInterfaceProtocol;
uint8_t xdc_if_iInterface;
uint8_t xdc_ep_bLength;
uint8_t xdc_ep_bDescriptorType;
uint8_t xdc_ep_bEndpointAddress;
uint8_t xdc_ep_bmAttributes;
uint16_t xdc_ep_wMaxPacketSize;
uint8_t xdc_ep_bInterval;
uint8_t xdc_epssc_bLength;
uint8_t xdc_epssc_bDescriptorType;
uint8_t xdc_epssc_bMaxBurst;
uint8_t xdc_epssc_bmAttributes;
uint16_t xdc_epssc_wBytesPerInterval;
} xhci_dev_conf_t;
#pragma pack()
#if MAX_PORTS != 31
#error "MAX_PORTS has changed, update xdc_ep_wMaxPacketSize"
#endif
xhci_dev_conf_t xhci_hcdi_conf = {
.xdc_cfg_bLength = 0x9,
.xdc_cfg_bDescriptorType = USB_DESCR_TYPE_CFG,
#if defined(_BIG_ENDIAN)
.xdc_cfg_wTotalLength = 0x1f00,
#elif defined(_LITTLE_ENDIAN)
.xdc_cfg_wTotalLength = 0x001f,
#else
#error "Unknown endianness"
#endif
.xdc_cfg_bNumInterfaces = 0x1,
.xdc_cfg_bConfigurationValue = 0x1,
.xdc_cfg_iConfiguration = 0x0,
.xdc_cfg_bmAttributes = 0x40,
.xdc_cfg_bMaxPower = 0x0,
.xdc_if_bLength = 0x9,
.xdc_if_bDescriptorType = USB_DESCR_TYPE_IF,
.xdc_if_bInterfaceNumber = 0x0,
.xdc_if_bAlternateSetting = 0x0,
.xdc_if_bNumEndpoints = 0x1,
.xdc_if_bInterfaceClass = USB_CLASS_HUB,
.xdc_if_bInterfaceSubClass = 0x0,
.xdc_if_bInterfaceProtocol = 0x0,
.xdc_if_iInterface = 0x0,
.xdc_ep_bLength = 0x7,
.xdc_ep_bDescriptorType = USB_DESCR_TYPE_EP,
.xdc_ep_bEndpointAddress = USB_EP_DIR_IN | ROOT_HUB_ADDR,
.xdc_ep_bmAttributes = USB_EP_ATTR_INTR,
#if defined(_BIG_ENDIAN)
.xdc_ep_wMaxPacketSize = 0x0400,
#elif defined(_LITTLE_ENDIAN)
.xdc_ep_wMaxPacketSize = 0x0004,
#else
#error "Unknown endianness"
#endif
.xdc_ep_bInterval = 0x8,
.xdc_epssc_bLength = 0x06,
.xdc_epssc_bDescriptorType = USB_DESCR_TYPE_SS_EP_COMP,
.xdc_epssc_bMaxBurst = 0,
.xdc_epssc_bmAttributes = 0,
#if defined(_BIG_ENDIAN)
.xdc_epssc_wBytesPerInterval = 0x0200
#elif defined(_LITTLE_ENDIAN)
.xdc_epssc_wBytesPerInterval = 0x0002
#else
#error "Unknown endianness"
#endif
};
static int
xhci_root_hub_get_device_status(xhci_t *xhcip, usb_ctrl_req_t *ucrp)
{
uint16_t stand;
uint32_t psm;
uint8_t len;
mblk_t *mp;
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
mp = ucrp->ctrl_data;
switch (ucrp->ctrl_wValue) {
case USB_GET_STATUS_STANDARD:
if (ucrp->ctrl_wLength != USB_GET_STATUS_LEN)
return (USB_CR_UNSPECIFIED_ERR);
len = USB_GET_STATUS_LEN;
stand = LE_16(USB_DEV_SLF_PWRD_STATUS);
bcopy(&stand, mp->b_wptr, sizeof (stand));
break;
case USB_GET_STATUS_PTM:
if (ucrp->ctrl_wLength != USB_GET_STATUS_PTM_LEN)
return (USB_CR_UNSPECIFIED_ERR);
len = USB_GET_STATUS_PTM_LEN;
psm = 0;
bcopy(&psm, mp->b_wptr, sizeof (psm));
break;
default:
return (USB_CR_NOT_SUPPORTED);
}
mp->b_wptr += len;
return (USB_CR_OK);
}
static int
xhci_root_hub_get_status(xhci_t *xhcip, usb_ctrl_req_t *ucrp)
{
const uint32_t status = 0;
mblk_t *mp;
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
if (ucrp->ctrl_wLength != HUB_GET_STATUS_LEN)
return (USB_CR_UNSPECIFIED_ERR);
mp = ucrp->ctrl_data;
bcopy(&status, mp->b_wptr, sizeof (status));
mp->b_wptr += sizeof (status);
return (USB_CR_OK);
}
static void
xhci_root_hub_get_descriptor(xhci_t *xhcip, usb_ctrl_req_t *ucrp)
{
int len = MIN(sizeof (usb_ss_hub_descr_t), ucrp->ctrl_wLength);
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
bcopy(&xhcip->xhci_usba.xa_hub_descr, ucrp->ctrl_data->b_wptr, len);
ucrp->ctrl_data->b_wptr += len;
}
static int
xhci_root_hub_handle_port_clear_feature(xhci_t *xhcip, usb_ctrl_req_t *ucrp)
{
int feat = ucrp->ctrl_wValue;
int port = XHCI_PS_INDPORT(ucrp->ctrl_wIndex);
uint32_t reg;
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
if (port < 1 || port > xhcip->xhci_caps.xcap_max_ports)
return (USB_CR_UNSPECIFIED_ERR);
if (ucrp->ctrl_wLength != 0)
return (USB_CR_UNSPECIFIED_ERR);
reg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_PORTSC(port));
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to read port status register for "
"port %d: encountered fatal FM error, resetting device",
port);
xhci_fm_runtime_reset(xhcip);
return (USB_CR_HC_HARDWARE_ERR);
}
reg &= ~XHCI_PS_CLEAR;
switch (feat) {
case CFS_PORT_ENABLE:
reg |= XHCI_PS_PED;
break;
case CFS_PORT_POWER:
reg &= ~XHCI_PS_PP;
break;
case CFS_C_PORT_CONNECTION:
reg |= XHCI_PS_CSC;
break;
case CFS_C_PORT_RESET:
reg |= XHCI_PS_PRC;
break;
case CFS_C_PORT_OVER_CURRENT:
reg |= XHCI_PS_OCC;
break;
case CFS_C_PORT_SUSPEND:
case CFS_C_PORT_LINK_STATE:
reg |= XHCI_PS_PLC;
break;
case CFS_C_PORT_ENABLE:
reg |= XHCI_PS_PEC;
break;
case CFS_C_PORT_CONFIG_ERROR:
reg |= XHCI_PS_CEC;
break;
case CFS_C_BH_PORT_RESET:
reg |= XHCI_PS_WRC;
break;
case CFS_PORT_SUSPEND:
default:
xhci_log(xhcip, "!asked to clear unsupported root hub "
"feature %d on port %d", feat, port);
return (USB_CR_NOT_SUPPORTED);
}
xhci_put32(xhcip, XHCI_R_OPER, XHCI_PORTSC(port), reg);
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to write port status register for "
"port %d: encountered fatal FM error, resetting device",
port);
xhci_fm_runtime_reset(xhcip);
return (USB_CR_HC_HARDWARE_ERR);
}
return (USB_CR_OK);
}
static int
xhci_root_hub_handle_port_set_feature(xhci_t *xhcip, usb_ctrl_req_t *ucrp)
{
int feat = ucrp->ctrl_wValue;
int port = XHCI_PS_INDPORT(ucrp->ctrl_wIndex);
uint32_t val = XHCI_PS_INDVAL(ucrp->ctrl_wIndex);
uint32_t reg;
uintptr_t index;
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
if (port < 1 || port > xhcip->xhci_caps.xcap_max_ports)
return (USB_CR_UNSPECIFIED_ERR);
if (ucrp->ctrl_wLength != 0)
return (USB_CR_UNSPECIFIED_ERR);
index = XHCI_PORTSC(port);
reg = xhci_get32(xhcip, XHCI_R_OPER, index);
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to read port status register for "
"port %d: encountered fatal FM error, resetting device",
port);
xhci_fm_runtime_reset(xhcip);
return (USB_CR_HC_HARDWARE_ERR);
}
reg &= ~XHCI_PS_CLEAR;
switch (feat) {
case CFS_PORT_U1_TIMEOUT:
index = XHCI_PORTPMSC(port);
reg = xhci_get32(xhcip, XHCI_R_OPER, index);
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to read port power "
"management register for port %d: encountered "
"fatal FM error, resetting device", port);
xhci_fm_runtime_reset(xhcip);
return (USB_CR_HC_HARDWARE_ERR);
}
reg &= ~XHCI_PM3_U1TO_SET(0xff);
reg |= XHCI_PM3_U1TO_SET(val);
break;
case CFS_PORT_U2_TIMEOUT:
index = XHCI_PORTPMSC(port);
reg = xhci_get32(xhcip, XHCI_R_OPER, index);
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to read port power "
"management register for port %d: encountered "
"fatal FM error, resetting device", port);
xhci_fm_runtime_reset(xhcip);
return (USB_CR_HC_HARDWARE_ERR);
}
reg &= ~XHCI_PM3_U1TO_SET(0xff);
reg |= XHCI_PM3_U1TO_SET(val);
break;
case CFS_PORT_LINK_STATE:
reg |= XHCI_PS_PLS_SET(val);
reg |= XHCI_PS_LWS;
break;
case CFS_PORT_REMOTE_WAKE_MASK:
if (val & CFS_PRWM_CONN_ENABLE)
reg |= XHCI_PS_WCE;
else
reg &= ~XHCI_PS_WCE;
if (val & CFS_PRWM_DISCONN_ENABLE)
reg |= XHCI_PS_WDE;
else
reg &= ~XHCI_PS_WDE;
if (val & CFS_PRWM_OC_ENABLE)
reg |= XHCI_PS_WOE;
else
reg &= ~XHCI_PS_WOE;
break;
case CFS_BH_PORT_RESET:
reg |= XHCI_PS_WPR;
break;
case CFS_PORT_RESET:
reg |= XHCI_PS_PR;
break;
case CFS_PORT_POWER:
reg |= XHCI_PS_PP;
break;
case CFS_PORT_ENABLE:
return (USB_CR_OK);
case CFS_PORT_SUSPEND:
default:
xhci_log(xhcip, "!asked to set unsupported root hub "
"feature %d on port %d", feat, port);
return (USB_CR_NOT_SUPPORTED);
}
xhci_put32(xhcip, XHCI_R_OPER, index, reg);
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to write port status register for "
"port %d: encountered fatal FM error, resetting device",
port);
xhci_fm_runtime_reset(xhcip);
return (USB_CR_HC_HARDWARE_ERR);
}
return (USB_CR_OK);
}
static int
xhci_root_hub_handle_port_get_status(xhci_t *xhcip, usb_ctrl_req_t *ucrp)
{
uint32_t reg;
uint16_t ps, cs;
mblk_t *mp = ucrp->ctrl_data;
int port = XHCI_PS_INDPORT(ucrp->ctrl_wIndex);
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
if (port < 1 || port > xhcip->xhci_caps.xcap_max_ports)
return (USB_CR_UNSPECIFIED_ERR);
if (ucrp->ctrl_wValue != PORT_GET_STATUS_PORT)
return (USB_CR_NOT_SUPPORTED);
if (ucrp->ctrl_wLength != PORT_GET_STATUS_PORT_LEN)
return (USB_CR_UNSPECIFIED_ERR);
reg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_PORTSC(port));
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to read port status register for "
"port %d: encountered fatal FM error, resetting device",
port);
xhci_fm_runtime_reset(xhcip);
return (USB_CR_HC_HARDWARE_ERR);
}
ps = cs = 0;
if (reg & XHCI_PS_CCS)
ps |= PORT_STATUS_CCS;
if (reg & XHCI_PS_PED)
ps |= PORT_STATUS_PES;
if (reg & XHCI_PS_OCA)
ps |= PORT_STATUS_POCI;
if (reg & XHCI_PS_PR)
ps |= PORT_STATUS_PRS;
ps |= XHCI_PS_PLS_SET(XHCI_PS_PLS_GET(reg));
if (reg & XHCI_PS_PP)
ps |= PORT_STATUS_PPS;
switch (XHCI_PS_SPEED_GET(reg)) {
case XHCI_SPEED_FULL:
ps |= USBA_FULL_SPEED_DEV << PORT_STATUS_SPSHIFT_SS;
break;
case XHCI_SPEED_LOW:
ps |= USBA_LOW_SPEED_DEV << PORT_STATUS_SPSHIFT_SS;
break;
case XHCI_SPEED_HIGH:
ps |= USBA_HIGH_SPEED_DEV << PORT_STATUS_SPSHIFT_SS;
break;
case XHCI_SPEED_SUPER:
default:
ps |= USBA_SUPER_SPEED_DEV << PORT_STATUS_SPSHIFT_SS;
break;
}
if (reg & XHCI_PS_CSC)
cs |= PORT_CHANGE_CSC;
if (reg & XHCI_PS_PEC)
cs |= PORT_CHANGE_PESC;
if (reg & XHCI_PS_OCC)
cs |= PORT_CHANGE_OCIC;
if (reg & XHCI_PS_PRC)
cs |= PORT_CHANGE_PRSC;
if (reg & XHCI_PS_WRC)
cs |= PORT_CHANGE_BHPR;
if (reg & XHCI_PS_PLC)
cs |= PORT_CHANGE_PLSC;
if (reg & XHCI_PS_CEC)
cs |= PORT_CHANGE_PCE;
cs = LE_16(cs);
ps = LE_16(ps);
bcopy(&ps, mp->b_wptr, sizeof (uint16_t));
mp->b_wptr += sizeof (uint16_t);
bcopy(&cs, mp->b_wptr, sizeof (uint16_t));
mp->b_wptr += sizeof (uint16_t);
return (USB_CR_OK);
}
int
xhci_root_hub_ctrl_req(xhci_t *xhcip, usba_pipe_handle_data_t *ph,
usb_ctrl_req_t *ucrp)
{
int ret = USB_CR_OK;
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
switch (ucrp->ctrl_bmRequestType) {
case HUB_GET_DEVICE_STATUS_TYPE:
ret = xhci_root_hub_get_device_status(xhcip, ucrp);
break;
case HUB_HANDLE_PORT_FEATURE_TYPE:
switch (ucrp->ctrl_bRequest) {
case USB_REQ_CLEAR_FEATURE:
ret = xhci_root_hub_handle_port_clear_feature(xhcip,
ucrp);
break;
case USB_REQ_SET_FEATURE:
ret = xhci_root_hub_handle_port_set_feature(xhcip,
ucrp);
break;
default:
ret = USB_CR_NOT_SUPPORTED;
break;
}
break;
case HUB_GET_PORT_STATUS_TYPE:
ret = xhci_root_hub_handle_port_get_status(xhcip, ucrp);
break;
case HUB_CLASS_REQ_TYPE:
switch (ucrp->ctrl_bRequest) {
case USB_REQ_GET_STATUS:
ret = xhci_root_hub_get_status(xhcip, ucrp);
break;
case USB_REQ_GET_DESCR:
xhci_root_hub_get_descriptor(xhcip, ucrp);
break;
default:
xhci_error(xhcip, "Unhandled hub request: 0x%x",
ucrp->ctrl_bRequest);
ret = USB_CR_NOT_SUPPORTED;
break;
}
break;
default:
xhci_error(xhcip, "Unhandled hub request type: %x",
ucrp->ctrl_bmRequestType);
ret = USB_CR_NOT_SUPPORTED;
break;
}
mutex_exit(&xhcip->xhci_lock);
usba_hcdi_cb(ph, (usb_opaque_t)ucrp, ret);
mutex_enter(&xhcip->xhci_lock);
return (USB_SUCCESS);
}
void
xhci_root_hub_psc_callback(xhci_t *xhcip)
{
usb_intr_req_t *req, *new;
usba_pipe_handle_data_t *ph;
mblk_t *mp;
uint32_t mask;
unsigned i;
mask = 0;
for (i = 0; i <= xhcip->xhci_caps.xcap_max_ports; i++) {
uint32_t reg;
reg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_PORTSC(i));
if ((reg & XHCI_HUB_INTR_CHANGE_MASK) != 0)
mask |= 1UL << i;
}
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "failed to read port status registers: "
"encountered fatal FM error, resetting device");
xhci_fm_runtime_reset(xhcip);
return;
}
if (mask == 0)
return;
mask = LE_32(mask);
mutex_enter(&xhcip->xhci_lock);
if (xhcip->xhci_usba.xa_intr_cb_req == NULL) {
mutex_exit(&xhcip->xhci_lock);
return;
}
ASSERT(xhcip->xhci_usba.xa_intr_cb_ph != NULL);
req = xhcip->xhci_usba.xa_intr_cb_req;
ph = xhcip->xhci_usba.xa_intr_cb_ph;
new = usba_hcdi_dup_intr_req(ph->p_dip, req, req->intr_len, 0);
if (new == NULL) {
new = xhcip->xhci_usba.xa_intr_cb_req;
xhcip->xhci_usba.xa_intr_cb_req = NULL;
mutex_exit(&xhcip->xhci_lock);
usba_hcdi_cb(ph, (usb_opaque_t)new, USB_CR_NO_RESOURCES);
return;
}
mutex_enter(&ph->p_mutex);
ph->p_req_count++;
mutex_exit(&ph->p_mutex);
mp = new->intr_data;
bcopy(&mask, mp->b_wptr, sizeof (mask));
mp->b_wptr += sizeof (mask);
mutex_exit(&xhcip->xhci_lock);
usba_hcdi_cb(ph, (usb_opaque_t)new, USB_CR_OK);
}
void
xhci_root_hub_intr_root_disable(xhci_t *xhcip)
{
usba_pipe_handle_data_t *ph;
usb_intr_req_t *uirp;
ASSERT(MUTEX_HELD(&xhcip->xhci_lock));
ph = xhcip->xhci_usba.xa_intr_cb_ph;
xhcip->xhci_usba.xa_intr_cb_ph = NULL;
ASSERT(ph != NULL);
uirp = xhcip->xhci_usba.xa_intr_cb_req;
xhcip->xhci_usba.xa_intr_cb_req = NULL;
if (uirp == NULL) {
return;
}
mutex_exit(&xhcip->xhci_lock);
usba_hcdi_cb(ph, (usb_opaque_t)uirp, USB_CR_STOPPED_POLLING);
mutex_enter(&xhcip->xhci_lock);
}
int
xhci_root_hub_intr_root_enable(xhci_t *xhcip, usba_pipe_handle_data_t *ph,
usb_intr_req_t *uirp)
{
ASSERT((ph->p_ep.bEndpointAddress & USB_EP_NUM_MASK) == 1);
ASSERT((uirp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
mutex_enter(&xhcip->xhci_lock);
if (xhcip->xhci_state & XHCI_S_ERROR) {
mutex_exit(&xhcip->xhci_lock);
return (USB_HC_HARDWARE_ERROR);
}
if (xhcip->xhci_usba.xa_intr_cb_ph != NULL) {
mutex_exit(&xhcip->xhci_lock);
return (USB_BUSY);
}
xhcip->xhci_usba.xa_intr_cb_ph = ph;
xhcip->xhci_usba.xa_intr_cb_req = uirp;
mutex_exit(&xhcip->xhci_lock);
xhci_root_hub_psc_callback(xhcip);
return (USB_SUCCESS);
}
int
xhci_root_hub_fini(xhci_t *xhcip)
{
if (usba_hubdi_unbind_root_hub(xhcip->xhci_dip) != USB_SUCCESS)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
static int
xhci_root_hub_fill_hub_desc(xhci_t *xhcip)
{
int i;
uint16_t chars;
usb_ss_hub_descr_t *hdp = &xhcip->xhci_usba.xa_hub_descr;
bzero(hdp, sizeof (usb_ss_hub_descr_t));
hdp->bDescLength = sizeof (usb_ss_hub_descr_t);
hdp->bDescriptorType = ROOT_HUB_SS_DESCRIPTOR_TYPE;
hdp->bNbrPorts = xhcip->xhci_caps.xcap_max_ports;
chars = 0;
if (xhcip->xhci_caps.xcap_flags & XCAP_PPC)
chars |= HUB_CHARS_INDIVIDUAL_PORT_POWER;
chars |= HUB_CHARS_INDIV_OVER_CURRENT;
hdp->wHubCharacteristics = LE_16(chars);
hdp->bPwrOn2PwrGood = XHCI_POWER_GOOD;
hdp->bHubContrCurrent = 0;
hdp->bHubHdrDecLat = 0;
hdp->wHubDelay = 0;
for (i = 1; i < xhcip->xhci_caps.xcap_max_ports; i++) {
uint32_t reg;
reg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_PORTSC(i));
if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
xhci_error(xhcip, "encountered fatal FM error while "
"reading port status register %d", i);
ddi_fm_service_impact(xhcip->xhci_dip,
DDI_SERVICE_LOST);
return (EIO);
}
if (reg & XHCI_PS_DR)
hdp->DeviceRemovable[i / 8] |= 1U << (i % 8);
}
return (0);
}
static uint16_t
xhci_root_vers_to_bcd(uint8_t vers)
{
uint8_t major, minor;
major = (vers & 0xf0) >> 4;
minor = (vers & 0x0f);
return ((major << 8) | minor);
}
static void
xhci_root_hub_fill_dev_desc(xhci_t *xhcip, usb_dev_descr_t *hub)
{
hub->bLength = sizeof (usb_dev_descr_t);
hub->bDescriptorType = 0x01;
hub->bcdUSB = xhci_root_vers_to_bcd(xhcip->xhci_caps.xcap_usb_vers);
hub->bDeviceClass = USB_CLASS_HUB;
hub->bDeviceSubClass = 0x00;
hub->bDeviceProtocol = 0x03;
hub->bMaxPacketSize0 = 9;
hub->idVendor = 0x00;
hub->idProduct = 0x00;
hub->bcdDevice = 0x00;
hub->iManufacturer = 0x00;
hub->iProduct = 0x00;
hub->iSerialNumber = 0x00;
hub->bNumConfigurations = 0x01;
}
int
xhci_root_hub_init(xhci_t *xhcip)
{
usb_dev_descr_t *hub = &xhcip->xhci_usba.xa_dev_descr;
uchar_t *conf = (uchar_t *)&xhci_hcdi_conf;
xhci_root_hub_fill_dev_desc(xhcip, hub);
if (xhci_root_hub_fill_hub_desc(xhcip) != 0)
return (DDI_FAILURE);
if (usba_hubdi_bind_root_hub(xhcip->xhci_dip, conf,
sizeof (xhci_hcdi_conf), hub) != USB_SUCCESS)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}