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
52326Ssl147100 * Common Development and Distribution License (the "License").
62326Ssl147100 * 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 /*
22*6898Sfb209375 * 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 * Open Host Controller Driver (OHCI)
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * The USB Open Host Controller driver is a software driver which interfaces
310Sstevel@tonic-gate * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
32*6898Sfb209375 * The interface to USB Open Host Controller is defined by the OpenHCI Host
330Sstevel@tonic-gate * Controller Interface.
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * This module contains the code for root hub related functions.
360Sstevel@tonic-gate *
370Sstevel@tonic-gate * Note: ONE_XFER is not supported on root hub interrupt polling.
380Sstevel@tonic-gate */
390Sstevel@tonic-gate #include <sys/usb/hcd/openhci/ohcid.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate /* static function prototypes */
420Sstevel@tonic-gate static int ohci_handle_set_clear_port_feature(
430Sstevel@tonic-gate ohci_state_t *ohcip,
440Sstevel@tonic-gate uchar_t bRequest,
450Sstevel@tonic-gate uint16_t wValue,
460Sstevel@tonic-gate uint16_t port);
470Sstevel@tonic-gate static void ohci_handle_port_power(ohci_state_t *ohcip,
480Sstevel@tonic-gate uint16_t port,
490Sstevel@tonic-gate uint_t on);
500Sstevel@tonic-gate static void ohci_handle_port_enable(ohci_state_t *ohcip,
510Sstevel@tonic-gate uint16_t port,
520Sstevel@tonic-gate uint_t on);
530Sstevel@tonic-gate static void ohci_handle_clrchng_port_enable(
540Sstevel@tonic-gate ohci_state_t *ohcip,
550Sstevel@tonic-gate uint16_t port);
560Sstevel@tonic-gate static void ohci_handle_port_suspend(ohci_state_t *ohcip,
570Sstevel@tonic-gate uint16_t port,
580Sstevel@tonic-gate uint_t on);
590Sstevel@tonic-gate static void ohci_handle_clrchng_port_suspend(
600Sstevel@tonic-gate ohci_state_t *ohcip,
610Sstevel@tonic-gate uint16_t port);
620Sstevel@tonic-gate static void ohci_handle_port_reset(ohci_state_t *ohcip,
630Sstevel@tonic-gate uint16_t port);
640Sstevel@tonic-gate static void ohci_handle_complete_port_reset(
650Sstevel@tonic-gate ohci_state_t *ohcip,
660Sstevel@tonic-gate uint16_t port);
670Sstevel@tonic-gate static void ohci_handle_clear_port_connection(
680Sstevel@tonic-gate ohci_state_t *ohcip,
690Sstevel@tonic-gate uint16_t port);
700Sstevel@tonic-gate static void ohci_handle_clrchng_port_over_current(
710Sstevel@tonic-gate ohci_state_t *ohcip,
720Sstevel@tonic-gate uint16_t port);
730Sstevel@tonic-gate static void ohci_handle_get_port_status(
740Sstevel@tonic-gate ohci_state_t *ohcip,
750Sstevel@tonic-gate uint16_t port);
762326Ssl147100 static int ohci_handle_set_clear_hub_feature(
772326Ssl147100 ohci_state_t *ohcip,
782326Ssl147100 uchar_t bRequest,
792326Ssl147100 uint16_t wValue);
802326Ssl147100 static void ohci_handle_clrchng_hub_over_current(
812326Ssl147100 ohci_state_t *ohcip);
820Sstevel@tonic-gate static void ohci_handle_get_hub_descriptor(
830Sstevel@tonic-gate ohci_state_t *ohcip);
840Sstevel@tonic-gate static void ohci_handle_get_hub_status(
850Sstevel@tonic-gate ohci_state_t *ohcip);
861001Ssl147100 static void ohci_handle_get_device_status(
871001Ssl147100 ohci_state_t *ohcip);
880Sstevel@tonic-gate static int ohci_root_hub_allocate_intr_pipe_resource(
890Sstevel@tonic-gate ohci_state_t *ohcip,
900Sstevel@tonic-gate usb_flags_t flags);
910Sstevel@tonic-gate static void ohci_root_hub_intr_pipe_cleanup(
920Sstevel@tonic-gate ohci_state_t *ohcip,
930Sstevel@tonic-gate usb_cr_t completion_reason);
940Sstevel@tonic-gate static void ohci_root_hub_hcdi_callback(
950Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
960Sstevel@tonic-gate usb_cr_t completion_reason);
970Sstevel@tonic-gate
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * ohci_init_root_hub:
1010Sstevel@tonic-gate *
1020Sstevel@tonic-gate * Initialize the root hub
1030Sstevel@tonic-gate */
1040Sstevel@tonic-gate int
ohci_init_root_hub(ohci_state_t * ohcip)1050Sstevel@tonic-gate ohci_init_root_hub(ohci_state_t *ohcip)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr =
108*6898Sfb209375 &ohcip->ohci_root_hub.rh_descr;
1090Sstevel@tonic-gate uint_t des_A, des_B, port_state;
1100Sstevel@tonic-gate int i, length;
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1130Sstevel@tonic-gate "ohci_init_root_hub:");
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /* Read the descriptor registers */
1160Sstevel@tonic-gate des_A = ohcip->ohci_root_hub.rh_des_A = Get_OpReg(hcr_rh_descriptorA);
1170Sstevel@tonic-gate des_B = ohcip->ohci_root_hub.rh_des_B = Get_OpReg(hcr_rh_descriptorB);
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1200Sstevel@tonic-gate "root hub descriptor A 0x%x", ohcip->ohci_root_hub.rh_des_A);
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1230Sstevel@tonic-gate "root hub descriptor B 0x%x", ohcip->ohci_root_hub.rh_des_B);
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate /* Obtain the root hub status */
1260Sstevel@tonic-gate ohcip->ohci_root_hub.rh_status = Get_OpReg(hcr_rh_status);
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate /*
1290Sstevel@tonic-gate * Build the hub descriptor based on HcRhDescriptorA and
1300Sstevel@tonic-gate * HcRhDescriptorB
1310Sstevel@tonic-gate */
1320Sstevel@tonic-gate root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate if ((des_A & HCR_RHA_NDP) > OHCI_MAX_RH_PORTS) {
1350Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1360Sstevel@tonic-gate "ohci_init_root_hub:" "Invalid no of root hub ports 0x%x",
1370Sstevel@tonic-gate des_A & HCR_RHA_NDP);
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate return (USB_FAILURE);
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /* Obtain the number of downstream ports */
1430Sstevel@tonic-gate root_hub_descr->bNbrPorts = des_A & HCR_RHA_NDP;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate length = root_hub_descr->bNbrPorts / 8;
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate if (length) {
1480Sstevel@tonic-gate root_hub_descr->bDescLength = 7 + (2 * (length + 1));
1490Sstevel@tonic-gate } else {
1500Sstevel@tonic-gate root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate /* Determine the Power Switching Mode */
1540Sstevel@tonic-gate if (!(des_A & HCR_RHA_NPS)) {
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate * The ports are power switched. Check for either individual
1570Sstevel@tonic-gate * or gang power switching.
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate if ((des_A & HCR_RHA_PSM) && (des_B & HCR_RHB_PPCM)) {
1600Sstevel@tonic-gate /* each port is powered individually */
1610Sstevel@tonic-gate root_hub_descr->wHubCharacteristics =
1620Sstevel@tonic-gate HUB_CHARS_INDIVIDUAL_PORT_POWER;
1630Sstevel@tonic-gate } else {
1640Sstevel@tonic-gate /* the ports are gang powered */
1650Sstevel@tonic-gate root_hub_descr->
1660Sstevel@tonic-gate wHubCharacteristics = HUB_CHARS_GANGED_POWER;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /* Each port will start off in the POWERED_OFF mode */
1700Sstevel@tonic-gate port_state = POWERED_OFF;
1710Sstevel@tonic-gate } else {
1720Sstevel@tonic-gate /* The ports are powered when the ctlr is powered */
1730Sstevel@tonic-gate root_hub_descr->
1740Sstevel@tonic-gate wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING;
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate port_state = DISCONNECTED;
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate /* The root hub should never be a compound device */
1800Sstevel@tonic-gate ASSERT((des_A & HCR_RHA_DT) == 0);
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate /* Determine the Over-current Protection Mode */
1830Sstevel@tonic-gate if (des_A & HCR_RHA_NOCP) {
1840Sstevel@tonic-gate /* No over current protection */
1850Sstevel@tonic-gate root_hub_descr->
1860Sstevel@tonic-gate wHubCharacteristics |= HUB_CHARS_NO_OVER_CURRENT;
1870Sstevel@tonic-gate } else {
1880Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1890Sstevel@tonic-gate ohcip->ohci_log_hdl, "OCPM =%d, PSM=%d",
1900Sstevel@tonic-gate des_A & HCR_RHA_OCPM, des_A & HCR_RHA_PSM);
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate /* See if over current protection is provided */
1930Sstevel@tonic-gate if (des_A & HCR_RHA_OCPM) {
1940Sstevel@tonic-gate /* reported on a per port basis */
1950Sstevel@tonic-gate root_hub_descr->
1960Sstevel@tonic-gate wHubCharacteristics |= HUB_CHARS_INDIV_OVER_CURRENT;
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate /* Obtain the power on to power good time of the ports */
2010Sstevel@tonic-gate root_hub_descr->bPwrOn2PwrGood = (uint32_t)
2020Sstevel@tonic-gate ((des_A & HCR_RHA_PTPGT) >> HCR_RHA_PTPGT_SHIFT);
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2050Sstevel@tonic-gate "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood);
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /* Indicate if the device is removable */
2080Sstevel@tonic-gate root_hub_descr->DeviceRemovable = (uchar_t)des_B & HCR_RHB_DR;
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate * Fill in the port power control mask:
2120Sstevel@tonic-gate * Each bit in the PortPowerControlMask
2130Sstevel@tonic-gate * should be set. Refer to USB 2.0, table 11-13
2140Sstevel@tonic-gate */
2150Sstevel@tonic-gate root_hub_descr->PortPwrCtrlMask = (uchar_t)(des_B >> 16);
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate /* Set the state of each port and initialize the status */
2180Sstevel@tonic-gate for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
2190Sstevel@tonic-gate ohcip->ohci_root_hub.rh_port_state[i] = port_state;
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate /* Turn off the power on each port for now */
2220Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[i], HCR_PORT_CPP);
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate * Initialize each of the root hub port status
2260Sstevel@tonic-gate * equal to zero. This initialization makes sure
2270Sstevel@tonic-gate * that all devices connected to root hub will
2280Sstevel@tonic-gate * enumerates when the first RHSC interrupt occurs
2290Sstevel@tonic-gate * since definitely there will be changes in
2300Sstevel@tonic-gate * the root hub port status.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate ohcip->ohci_root_hub.rh_port_status[i] = 0;
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate return (USB_SUCCESS);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate * ohci_load_root_hub_driver:
2410Sstevel@tonic-gate *
2420Sstevel@tonic-gate * Attach the root hub
2430Sstevel@tonic-gate */
2440Sstevel@tonic-gate static usb_dev_descr_t ohci_root_hub_device_descriptor = {
2450Sstevel@tonic-gate 0x12, /* bLength */
2460Sstevel@tonic-gate 0x01, /* bDescriptorType, Device */
2470Sstevel@tonic-gate 0x110, /* bcdUSB, v1.1 */
2480Sstevel@tonic-gate 0x09, /* bDeviceClass */
2490Sstevel@tonic-gate 0x00, /* bDeviceSubClass */
2500Sstevel@tonic-gate 0x00, /* bDeviceProtocol */
2510Sstevel@tonic-gate 0x08, /* bMaxPacketSize0 */
2520Sstevel@tonic-gate 0x00, /* idVendor */
2530Sstevel@tonic-gate 0x00, /* idProduct */
2540Sstevel@tonic-gate 0x00, /* bcdDevice */
2550Sstevel@tonic-gate 0x00, /* iManufacturer */
2560Sstevel@tonic-gate 0x00, /* iProduct */
2570Sstevel@tonic-gate 0x00, /* iSerialNumber */
2580Sstevel@tonic-gate 0x01 /* bNumConfigurations */
2590Sstevel@tonic-gate };
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate static uchar_t ohci_root_hub_config_descriptor[] = {
2620Sstevel@tonic-gate /* One configuartion */
2630Sstevel@tonic-gate 0x09, /* bLength */
2640Sstevel@tonic-gate 0x02, /* bDescriptorType, Configuartion */
2650Sstevel@tonic-gate 0x19, 0x00, /* wTotalLength */
2660Sstevel@tonic-gate 0x01, /* bNumInterfaces */
2670Sstevel@tonic-gate 0x01, /* bConfigurationValue */
2680Sstevel@tonic-gate 0x00, /* iConfiguration */
2690Sstevel@tonic-gate 0x40, /* bmAttributes */
2700Sstevel@tonic-gate 0x00, /* MaxPower */
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /* One Interface */
2730Sstevel@tonic-gate 0x09, /* bLength */
2740Sstevel@tonic-gate 0x04, /* bDescriptorType, Interface */
2750Sstevel@tonic-gate 0x00, /* bInterfaceNumber */
2760Sstevel@tonic-gate 0x00, /* bAlternateSetting */
2770Sstevel@tonic-gate 0x01, /* bNumEndpoints */
2780Sstevel@tonic-gate 0x09, /* bInterfaceClass */
2790Sstevel@tonic-gate 0x01, /* bInterfaceSubClass */
2800Sstevel@tonic-gate 0x00, /* bInterfaceProtocol */
2810Sstevel@tonic-gate 0x00, /* iInterface */
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate /* One Endpoint (status change endpoint) */
2840Sstevel@tonic-gate 0x07, /* bLength */
2850Sstevel@tonic-gate 0x05, /* bDescriptorType, Endpoint */
2860Sstevel@tonic-gate 0x81, /* bEndpointAddress */
2870Sstevel@tonic-gate 0x03, /* bmAttributes */
288*6898Sfb209375 0x01, 0x00, /* wMaxPacketSize, 1 + (OHCI_MAX_RH_PORTS / 8) */
2890Sstevel@tonic-gate 0xff /* bInterval */
2900Sstevel@tonic-gate };
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate int
ohci_load_root_hub_driver(ohci_state_t * ohcip)2930Sstevel@tonic-gate ohci_load_root_hub_driver(ohci_state_t *ohcip)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
2960Sstevel@tonic-gate "ohci_load_root_hub_driver:");
2970Sstevel@tonic-gate
2980Sstevel@tonic-gate return (usba_hubdi_bind_root_hub(ohcip->ohci_dip,
2990Sstevel@tonic-gate ohci_root_hub_config_descriptor,
3000Sstevel@tonic-gate sizeof (ohci_root_hub_config_descriptor),
3010Sstevel@tonic-gate &ohci_root_hub_device_descriptor));
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /*
3060Sstevel@tonic-gate * ohci_unload_root_hub_driver:
3070Sstevel@tonic-gate */
3080Sstevel@tonic-gate int
ohci_unload_root_hub_driver(ohci_state_t * ohcip)3090Sstevel@tonic-gate ohci_unload_root_hub_driver(ohci_state_t *ohcip)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3120Sstevel@tonic-gate "ohci_unload_root_hub_driver:");
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate return (usba_hubdi_unbind_root_hub(ohcip->ohci_dip));
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate * ohci_handle_root_hub_pipe_open:
3200Sstevel@tonic-gate *
3210Sstevel@tonic-gate * Handle opening of control and interrupt pipes on root hub.
3220Sstevel@tonic-gate */
3230Sstevel@tonic-gate /* ARGSUSED */
3240Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)3250Sstevel@tonic-gate ohci_handle_root_hub_pipe_open(
3260Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
3270Sstevel@tonic-gate usb_flags_t usb_flags)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
330*6898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
3310Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3340Sstevel@tonic-gate "ohci_handle_root_hub_pipe_open: Root hub pipe open");
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
3370Sstevel@tonic-gate
3380Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
3390Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
3400Sstevel@tonic-gate /* Save control pipe handle */
3410Sstevel@tonic-gate ohcip->ohci_root_hub.rh_ctrl_pipe_handle = ph;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate /* Set state of the root hub control pipe as idle */
3440Sstevel@tonic-gate ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3490Sstevel@tonic-gate "ohci_handle_root_hub_pipe_open: Root hub control "
3500Sstevel@tonic-gate "pipe open succeeded");
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate break;
3530Sstevel@tonic-gate case USB_EP_ATTR_INTR:
3540Sstevel@tonic-gate /* Save interrupt pipe handle */
3550Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_handle = ph;
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate /* Set state of the root hub interrupt pipe as idle */
3580Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_IDLE;
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3650Sstevel@tonic-gate "ohci_handle_root_hub_pipe_open: Root hub interrupt "
3660Sstevel@tonic-gate "pipe open succeeded");
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate break;
3690Sstevel@tonic-gate default:
3700Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3710Sstevel@tonic-gate "ohci_handle_root_hub_pipe_open: Root hub pipe open"
3720Sstevel@tonic-gate "failed");
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate return (USB_FAILURE);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate ohcip->ohci_open_pipe_count++;
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate return (USB_SUCCESS);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate * ohci_handle_root_hub_pipe_close:
3850Sstevel@tonic-gate *
3860Sstevel@tonic-gate * Handle closing of control and interrupt pipes on root hub.
3870Sstevel@tonic-gate */
3880Sstevel@tonic-gate /* ARGSUSED */
3890Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t * ph)3900Sstevel@tonic-gate ohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t *ph)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
393*6898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
3940Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
3970Sstevel@tonic-gate "ohci_handle_root_hub_pipe_close: Root hub pipe close");
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
4020Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
4030Sstevel@tonic-gate ASSERT(ohcip->ohci_root_hub.
4040Sstevel@tonic-gate rh_ctrl_pipe_state != OHCI_PIPE_STATE_CLOSE);
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate /* Set state of the root hub control pipe as close */
4070Sstevel@tonic-gate ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_CLOSE;
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate /* Set root hub control pipe handle to null */
4100Sstevel@tonic-gate ohcip->ohci_root_hub.rh_ctrl_pipe_handle = NULL;
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4130Sstevel@tonic-gate "ohci_handle_root_hub_pipe_close: "
4140Sstevel@tonic-gate "Root hub control pipe close succeeded");
4150Sstevel@tonic-gate break;
4160Sstevel@tonic-gate case USB_EP_ATTR_INTR:
4170Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate ASSERT(ohcip->ohci_root_hub.
4200Sstevel@tonic-gate rh_intr_pipe_state != OHCI_PIPE_STATE_CLOSE);
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate /* Set state of the root hub interrupt pipe as close */
4230Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_CLOSE;
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate /* Do interrupt pipe cleanup */
4260Sstevel@tonic-gate ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_PIPE_CLOSING);
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate /* Set root hub interrupt pipe handle to null */
4290Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_handle = NULL;
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4320Sstevel@tonic-gate "ohci_handle_root_hub_pipe_close: "
4330Sstevel@tonic-gate "Root hub interrupt pipe close succeeded");
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate break;
4360Sstevel@tonic-gate default:
4370Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4380Sstevel@tonic-gate "ohci_handle_root_hub_pipe_close: "
4390Sstevel@tonic-gate "Root hub pipe close failed");
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate return (USB_FAILURE);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate ohcip->ohci_open_pipe_count--;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate return (USB_SUCCESS);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate * ohci_handle_root_hub_pipe_reset:
4520Sstevel@tonic-gate *
4530Sstevel@tonic-gate * Handle resetting of control and interrupt pipes on root hub.
4540Sstevel@tonic-gate */
4550Sstevel@tonic-gate /* ARGSUSED */
4560Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)4570Sstevel@tonic-gate ohci_handle_root_hub_pipe_reset(
4580Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
4590Sstevel@tonic-gate usb_flags_t usb_flags)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
462*6898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
4630Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
4640Sstevel@tonic-gate int error = USB_SUCCESS;
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4670Sstevel@tonic-gate "ohci_handle_root_hub_pipe_reset: Root hub pipe reset");
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
4720Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
4730Sstevel@tonic-gate ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4760Sstevel@tonic-gate "ohci_handle_root_hub_pipe_reset: Pipe reset"
4770Sstevel@tonic-gate "for the root hub control pipe successful");
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate break;
4800Sstevel@tonic-gate case USB_EP_ATTR_INTR:
4810Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate if ((ohcip->ohci_root_hub.rh_client_intr_reqp) &&
4840Sstevel@tonic-gate (ohcip->ohci_root_hub.rh_intr_pipe_state !=
4850Sstevel@tonic-gate OHCI_PIPE_STATE_IDLE)) {
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate ohcip->ohci_root_hub.
4880Sstevel@tonic-gate rh_intr_pipe_state = OHCI_PIPE_STATE_RESET;
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate /* Do interrupt pipe cleanup */
4910Sstevel@tonic-gate ohci_root_hub_intr_pipe_cleanup(
4920Sstevel@tonic-gate ohcip, USB_CR_PIPE_RESET);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate ASSERT(ohcip->ohci_root_hub.
4960Sstevel@tonic-gate rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
4990Sstevel@tonic-gate "ohci_handle_root_hub_pipe_reset: "
5000Sstevel@tonic-gate "Pipe reset for root hub interrupt pipe successful");
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate break;
5030Sstevel@tonic-gate default:
5040Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5050Sstevel@tonic-gate "ohci_handle_root_hub_pipe_reset: "
5060Sstevel@tonic-gate "Root hub pipe reset failed");
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate error = USB_FAILURE;
5090Sstevel@tonic-gate break;
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate return (error);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate /*
5190Sstevel@tonic-gate * ohci_handle_root_hub_request:
5200Sstevel@tonic-gate *
5210Sstevel@tonic-gate * Intercept a root hub request. Handle the root hub request through the
5220Sstevel@tonic-gate * registers
5230Sstevel@tonic-gate */
5240Sstevel@tonic-gate /* ARGSUSED */
5250Sstevel@tonic-gate int
ohci_handle_root_hub_request(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp)5260Sstevel@tonic-gate ohci_handle_root_hub_request(
5270Sstevel@tonic-gate ohci_state_t *ohcip,
5280Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
5290Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate uchar_t bmRequestType = ctrl_reqp->ctrl_bmRequestType;
5320Sstevel@tonic-gate uchar_t bRequest = ctrl_reqp->ctrl_bRequest;
5330Sstevel@tonic-gate uint16_t wValue = ctrl_reqp->ctrl_wValue;
5340Sstevel@tonic-gate uint16_t wIndex = ctrl_reqp->ctrl_wIndex;
5350Sstevel@tonic-gate uint16_t wLength = ctrl_reqp->ctrl_wLength;
5360Sstevel@tonic-gate mblk_t *data = ctrl_reqp->ctrl_data;
5370Sstevel@tonic-gate uint16_t port = wIndex - 1; /* Adjust for controller */
5380Sstevel@tonic-gate usb_cr_t completion_reason;
5390Sstevel@tonic-gate int error = USB_SUCCESS;
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5420Sstevel@tonic-gate "ohci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
5430Sstevel@tonic-gate bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate if (ohcip->ohci_root_hub.rh_ctrl_pipe_state != OHCI_PIPE_STATE_IDLE) {
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5500Sstevel@tonic-gate "ohci_handle_root_hub_request: Pipe is not idle");
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate return (USB_FAILURE);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate /* Save the current control request pointer */
5580Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp;
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate /* Set pipe state to active */
5610Sstevel@tonic-gate ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_ACTIVE;
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate switch (bmRequestType) {
5661001Ssl147100 case HUB_GET_DEVICE_STATUS_TYPE:
5671001Ssl147100 ohci_handle_get_device_status(ohcip);
5681001Ssl147100 break;
5691001Ssl147100 case HUB_HANDLE_PORT_FEATURE_TYPE:
5700Sstevel@tonic-gate error = ohci_handle_set_clear_port_feature(ohcip,
5710Sstevel@tonic-gate bRequest, wValue, port);
5720Sstevel@tonic-gate break;
5731001Ssl147100 case HUB_GET_PORT_STATUS_TYPE:
5740Sstevel@tonic-gate ohci_handle_get_port_status(ohcip, port);
5750Sstevel@tonic-gate break;
5761001Ssl147100 case HUB_CLASS_REQ_TYPE:
5770Sstevel@tonic-gate switch (bRequest) {
5780Sstevel@tonic-gate case USB_REQ_GET_STATUS:
5790Sstevel@tonic-gate ohci_handle_get_hub_status(ohcip);
5800Sstevel@tonic-gate break;
5810Sstevel@tonic-gate case USB_REQ_GET_DESCR:
5820Sstevel@tonic-gate ohci_handle_get_hub_descriptor(ohcip);
5830Sstevel@tonic-gate break;
5840Sstevel@tonic-gate default:
5850Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5860Sstevel@tonic-gate "ohci_handle_root_hub_request:"
5870Sstevel@tonic-gate "Unsupported request 0x%x", bRequest);
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate error = USB_FAILURE;
5900Sstevel@tonic-gate break;
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate break;
5932326Ssl147100 case HUB_HANDLE_HUB_FEATURE_TYPE:
5942326Ssl147100 error = ohci_handle_set_clear_hub_feature(ohcip,
5952326Ssl147100 bRequest, wValue);
5962326Ssl147100 break;
5970Sstevel@tonic-gate default:
5980Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
5990Sstevel@tonic-gate "ohci_handle_root_hub_request: "
6000Sstevel@tonic-gate "Unsupported request 0x%x", bmRequestType);
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate error = USB_FAILURE;
6030Sstevel@tonic-gate break;
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK;
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
6090Sstevel@tonic-gate ohci_root_hub_hcdi_callback(ph, completion_reason);
6100Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6130Sstevel@tonic-gate "ohci_handle_root_hub_request: error = %d", error);
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate return (USB_SUCCESS);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate /*
6200Sstevel@tonic-gate * ohci_handle_set_clear_port_feature:
6210Sstevel@tonic-gate */
6220Sstevel@tonic-gate static int
ohci_handle_set_clear_port_feature(ohci_state_t * ohcip,uchar_t bRequest,uint16_t wValue,uint16_t port)6230Sstevel@tonic-gate ohci_handle_set_clear_port_feature(
6240Sstevel@tonic-gate ohci_state_t *ohcip,
6250Sstevel@tonic-gate uchar_t bRequest,
6260Sstevel@tonic-gate uint16_t wValue,
6270Sstevel@tonic-gate uint16_t port)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate int error = USB_SUCCESS;
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6320Sstevel@tonic-gate "ohci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
6330Sstevel@tonic-gate bRequest, wValue, port);
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate switch (bRequest) {
6360Sstevel@tonic-gate case USB_REQ_SET_FEATURE:
6370Sstevel@tonic-gate switch (wValue) {
6380Sstevel@tonic-gate case CFS_PORT_ENABLE:
6390Sstevel@tonic-gate ohci_handle_port_enable(ohcip, port, 1);
6400Sstevel@tonic-gate break;
6410Sstevel@tonic-gate case CFS_PORT_SUSPEND:
6420Sstevel@tonic-gate ohci_handle_port_suspend(ohcip, port, 1);
6430Sstevel@tonic-gate break;
6440Sstevel@tonic-gate case CFS_PORT_RESET:
6450Sstevel@tonic-gate ohci_handle_port_reset(ohcip, port);
6460Sstevel@tonic-gate break;
6470Sstevel@tonic-gate case CFS_PORT_POWER:
6480Sstevel@tonic-gate ohci_handle_port_power(ohcip, port, 1);
6490Sstevel@tonic-gate break;
6500Sstevel@tonic-gate default:
6510Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6520Sstevel@tonic-gate "ohci_handle_set_clear_port_feature: "
6530Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6540Sstevel@tonic-gate
6550Sstevel@tonic-gate error = USB_FAILURE;
6560Sstevel@tonic-gate break;
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate break;
6590Sstevel@tonic-gate case USB_REQ_CLEAR_FEATURE:
6600Sstevel@tonic-gate switch (wValue) {
6610Sstevel@tonic-gate case CFS_PORT_ENABLE:
6620Sstevel@tonic-gate ohci_handle_port_enable(ohcip, port, 0);
6630Sstevel@tonic-gate break;
6640Sstevel@tonic-gate case CFS_C_PORT_ENABLE:
6650Sstevel@tonic-gate ohci_handle_clrchng_port_enable(ohcip, port);
6660Sstevel@tonic-gate break;
6670Sstevel@tonic-gate case CFS_PORT_SUSPEND:
6680Sstevel@tonic-gate ohci_handle_port_suspend(ohcip, port, 0);
6690Sstevel@tonic-gate break;
6700Sstevel@tonic-gate case CFS_C_PORT_SUSPEND:
6710Sstevel@tonic-gate ohci_handle_clrchng_port_suspend(ohcip, port);
6720Sstevel@tonic-gate break;
6730Sstevel@tonic-gate case CFS_C_PORT_RESET:
6740Sstevel@tonic-gate ohci_handle_complete_port_reset(ohcip, port);
6750Sstevel@tonic-gate break;
6760Sstevel@tonic-gate case CFS_PORT_POWER:
6770Sstevel@tonic-gate ohci_handle_port_power(ohcip, port, 0);
6780Sstevel@tonic-gate break;
6790Sstevel@tonic-gate case CFS_C_PORT_CONNECTION:
6800Sstevel@tonic-gate ohci_handle_clear_port_connection(ohcip, port);
6810Sstevel@tonic-gate break;
6820Sstevel@tonic-gate case CFS_C_PORT_OVER_CURRENT:
6830Sstevel@tonic-gate ohci_handle_clrchng_port_over_current(ohcip, port);
6840Sstevel@tonic-gate break;
6850Sstevel@tonic-gate default:
6860Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6870Sstevel@tonic-gate "ohci_handle_set_clear_port_feature: "
6880Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate error = USB_FAILURE;
6910Sstevel@tonic-gate break;
6920Sstevel@tonic-gate }
693*6898Sfb209375 break;
6940Sstevel@tonic-gate default:
6950Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
6960Sstevel@tonic-gate "ohci_handle_set_clear_port_feature: "
6970Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate error = USB_FAILURE;
7000Sstevel@tonic-gate break;
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate return (error);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate /*
7080Sstevel@tonic-gate * ohci_handle_port_power:
7090Sstevel@tonic-gate *
7100Sstevel@tonic-gate * Turn on a root hub port.
7110Sstevel@tonic-gate */
7120Sstevel@tonic-gate static void
ohci_handle_port_power(ohci_state_t * ohcip,uint16_t port,uint_t on)7130Sstevel@tonic-gate ohci_handle_port_power(
7140Sstevel@tonic-gate ohci_state_t *ohcip,
7150Sstevel@tonic-gate uint16_t port,
7160Sstevel@tonic-gate uint_t on)
7170Sstevel@tonic-gate {
7180Sstevel@tonic-gate usb_hub_descr_t *hub_descr;
7190Sstevel@tonic-gate uint_t port_status;
7200Sstevel@tonic-gate ohci_root_hub_t *rh;
7210Sstevel@tonic-gate uint_t p;
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
7240Sstevel@tonic-gate
7250Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
7260Sstevel@tonic-gate rh = &ohcip->ohci_root_hub;
7270Sstevel@tonic-gate hub_descr = &ohcip->ohci_root_hub.rh_descr;
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
7300Sstevel@tonic-gate "ohci_handle_port_power: port = 0x%x status = 0x%x on = %d",
7310Sstevel@tonic-gate port, port_status, on);
7320Sstevel@tonic-gate
7330Sstevel@tonic-gate if (on) {
7340Sstevel@tonic-gate /*
7350Sstevel@tonic-gate * If the port power is ganged, enable the power through
7360Sstevel@tonic-gate * the status registers, else enable the port power.
7370Sstevel@tonic-gate */
7380Sstevel@tonic-gate if ((hub_descr->wHubCharacteristics &
7390Sstevel@tonic-gate HUB_CHARS_POWER_SWITCHING_MODE) ==
7400Sstevel@tonic-gate HUB_CHARS_GANGED_POWER) {
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPSC);
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate for (p = 0; p < hub_descr->bNbrPorts; p++) {
7450Sstevel@tonic-gate rh->rh_port_status[p] = 0;
7460Sstevel@tonic-gate rh->rh_port_state[p] = DISCONNECTED;
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate } else {
7490Sstevel@tonic-gate /* See if the port power is already on */
7500Sstevel@tonic-gate if (!(port_status & HCR_PORT_PPS)) {
7510Sstevel@tonic-gate /* Turn the port on */
7520Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port],
7530Sstevel@tonic-gate HCR_PORT_PPS);
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate rh->rh_port_status[port] = 0;
7570Sstevel@tonic-gate rh->rh_port_state[port] = DISCONNECTED;
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate } else {
7600Sstevel@tonic-gate /*
7610Sstevel@tonic-gate * If the port power is ganged, disable the power through
7620Sstevel@tonic-gate * the status registers, else disable the port power.
7630Sstevel@tonic-gate */
7640Sstevel@tonic-gate if ((hub_descr->wHubCharacteristics &
7650Sstevel@tonic-gate HUB_CHARS_POWER_SWITCHING_MODE) ==
7660Sstevel@tonic-gate HUB_CHARS_GANGED_POWER) {
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPS);
7690Sstevel@tonic-gate
7700Sstevel@tonic-gate for (p = 0; p < hub_descr->bNbrPorts; p++) {
7710Sstevel@tonic-gate rh->rh_port_status[p] = 0;
7720Sstevel@tonic-gate rh->rh_port_state[p] = POWERED_OFF;
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate } else {
7750Sstevel@tonic-gate /* See if the port power is already OFF */
7760Sstevel@tonic-gate if ((port_status & HCR_PORT_PPS)) {
7770Sstevel@tonic-gate /* Turn the port OFF by writing LSSA bit */
7780Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port],
779*6898Sfb209375 HCR_PORT_LSDA);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate rh->rh_port_status[port] = 0;
7830Sstevel@tonic-gate rh->rh_port_state[port] = POWERED_OFF;
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
7880Sstevel@tonic-gate "ohci_handle_port_power done: "
7890Sstevel@tonic-gate "port = 0x%x status = 0x%x on = %d",
7900Sstevel@tonic-gate port, Get_OpReg(hcr_rh_portstatus[port]), on);
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate /*
7970Sstevel@tonic-gate * ohci_handle_port_enable:
7980Sstevel@tonic-gate *
7990Sstevel@tonic-gate * Handle port enable request.
8000Sstevel@tonic-gate */
8010Sstevel@tonic-gate static void
ohci_handle_port_enable(ohci_state_t * ohcip,uint16_t port,uint_t on)8020Sstevel@tonic-gate ohci_handle_port_enable(
8030Sstevel@tonic-gate ohci_state_t *ohcip,
8040Sstevel@tonic-gate uint16_t port,
8050Sstevel@tonic-gate uint_t on)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate uint_t port_status;
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
8140Sstevel@tonic-gate "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
8150Sstevel@tonic-gate port, port_status);
8160Sstevel@tonic-gate
8170Sstevel@tonic-gate if (on) {
8180Sstevel@tonic-gate /* See if the port enable is already on */
8190Sstevel@tonic-gate if (!(port_status & HCR_PORT_PES)) {
8200Sstevel@tonic-gate /* Enable the port */
8210Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PES);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate } else {
8240Sstevel@tonic-gate /* See if the port enable is already off */
8253026Syq193411 if (port_status & HCR_PORT_PES) {
8260Sstevel@tonic-gate /* disable the port by writing CCS bit */
8270Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CCS);
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate /*
8360Sstevel@tonic-gate * ohci_handle_clrchng_port_enable:
8370Sstevel@tonic-gate *
8380Sstevel@tonic-gate * Handle clear port enable change bit.
8390Sstevel@tonic-gate */
8400Sstevel@tonic-gate static void
ohci_handle_clrchng_port_enable(ohci_state_t * ohcip,uint16_t port)8410Sstevel@tonic-gate ohci_handle_clrchng_port_enable(
8420Sstevel@tonic-gate ohci_state_t *ohcip,
8430Sstevel@tonic-gate uint16_t port)
8440Sstevel@tonic-gate {
8450Sstevel@tonic-gate uint_t port_status;
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
8520Sstevel@tonic-gate "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
8530Sstevel@tonic-gate port, port_status);
8540Sstevel@tonic-gate
8550Sstevel@tonic-gate /* Clear the PortEnableStatusChange Bit */
8560Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PESC);
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate * ohci_handle_port_suspend:
8640Sstevel@tonic-gate *
8650Sstevel@tonic-gate * Handle port suspend/resume request.
8660Sstevel@tonic-gate */
8670Sstevel@tonic-gate static void
ohci_handle_port_suspend(ohci_state_t * ohcip,uint16_t port,uint_t on)8680Sstevel@tonic-gate ohci_handle_port_suspend(
8690Sstevel@tonic-gate ohci_state_t *ohcip,
8700Sstevel@tonic-gate uint16_t port,
8710Sstevel@tonic-gate uint_t on)
8720Sstevel@tonic-gate {
8730Sstevel@tonic-gate uint_t port_status;
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
8780Sstevel@tonic-gate
8790Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
8800Sstevel@tonic-gate "ohci_handle_port_suspend: port = 0x%x, status = 0x%x",
8810Sstevel@tonic-gate port, port_status);
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate if (on) {
8840Sstevel@tonic-gate /* Suspend the port */
8850Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSS);
8860Sstevel@tonic-gate } else {
8870Sstevel@tonic-gate /* To Resume, we write the POCI bit */
8880Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_POCI);
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate
8910Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate /*
8960Sstevel@tonic-gate * ohci_handle_clrchng_port_suspend:
8970Sstevel@tonic-gate *
8980Sstevel@tonic-gate * Handle port clear port suspend change bit.
8990Sstevel@tonic-gate */
9000Sstevel@tonic-gate static void
ohci_handle_clrchng_port_suspend(ohci_state_t * ohcip,uint16_t port)9010Sstevel@tonic-gate ohci_handle_clrchng_port_suspend(
9020Sstevel@tonic-gate ohci_state_t *ohcip,
9030Sstevel@tonic-gate uint16_t port)
9040Sstevel@tonic-gate {
9050Sstevel@tonic-gate uint_t port_status;
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9120Sstevel@tonic-gate "ohci_handle_clrchng_port_suspend: port = 0x%x, status = 0x%x",
9130Sstevel@tonic-gate port, port_status);
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSSC);
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate /*
9220Sstevel@tonic-gate * ohci_handle_port_reset:
9230Sstevel@tonic-gate *
9240Sstevel@tonic-gate * Perform a port reset.
9250Sstevel@tonic-gate */
9260Sstevel@tonic-gate static void
ohci_handle_port_reset(ohci_state_t * ohcip,uint16_t port)9270Sstevel@tonic-gate ohci_handle_port_reset(
9280Sstevel@tonic-gate ohci_state_t *ohcip,
9290Sstevel@tonic-gate uint16_t port)
9300Sstevel@tonic-gate {
9310Sstevel@tonic-gate uint_t port_status;
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
9340Sstevel@tonic-gate
9350Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9380Sstevel@tonic-gate "ohci_handle_port_reset: port = 0x%x status = 0x%x",
9390Sstevel@tonic-gate port, port_status);
9400Sstevel@tonic-gate
9410Sstevel@tonic-gate if (!(port_status & HCR_PORT_CCS)) {
9420Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9430Sstevel@tonic-gate "port_status & HCR_PORT_CCS == 0: "
9440Sstevel@tonic-gate "port = 0x%x status = 0x%x", port, port_status);
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate
9470Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRS);
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate /*
9540Sstevel@tonic-gate * ohci_handle_complete_port_reset:
9550Sstevel@tonic-gate *
9560Sstevel@tonic-gate * Perform a port reset change.
9570Sstevel@tonic-gate */
9580Sstevel@tonic-gate static void
ohci_handle_complete_port_reset(ohci_state_t * ohcip,uint16_t port)9590Sstevel@tonic-gate ohci_handle_complete_port_reset(
9600Sstevel@tonic-gate ohci_state_t *ohcip,
9610Sstevel@tonic-gate uint16_t port)
9620Sstevel@tonic-gate {
9630Sstevel@tonic-gate uint_t port_status;
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9700Sstevel@tonic-gate "ohci_handle_complete_port_reset: port = 0x%x status = 0x%x",
9710Sstevel@tonic-gate port, port_status);
9720Sstevel@tonic-gate
9730Sstevel@tonic-gate if (!(port_status & HCR_PORT_CCS)) {
9740Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
9750Sstevel@tonic-gate "port_status & HCR_PORT_CCS == 0: "
9760Sstevel@tonic-gate "port = 0x%x status = 0x%x", port, port_status);
9770Sstevel@tonic-gate }
9780Sstevel@tonic-gate
9790Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRSC);
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate /*
9860Sstevel@tonic-gate * ohci_handle_clear_port_connection:
9870Sstevel@tonic-gate *
9880Sstevel@tonic-gate * Perform a clear port connection.
9890Sstevel@tonic-gate */
9900Sstevel@tonic-gate static void
ohci_handle_clear_port_connection(ohci_state_t * ohcip,uint16_t port)9910Sstevel@tonic-gate ohci_handle_clear_port_connection(
9920Sstevel@tonic-gate ohci_state_t *ohcip,
9930Sstevel@tonic-gate uint16_t port)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate uint_t port_status;
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
9980Sstevel@tonic-gate
9990Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
10000Sstevel@tonic-gate
10010Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10020Sstevel@tonic-gate "ohci_handle_clear_port_connection: port = 0x%x"
10030Sstevel@tonic-gate "status = 0x%x", port, port_status);
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate /* Clear CSC bit */
10060Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CSC);
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate
10110Sstevel@tonic-gate
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate * ohci_handle_clrchng_port_over_current:
10140Sstevel@tonic-gate *
10150Sstevel@tonic-gate * Perform a clear over current condition.
10160Sstevel@tonic-gate */
10170Sstevel@tonic-gate static void
ohci_handle_clrchng_port_over_current(ohci_state_t * ohcip,uint16_t port)10180Sstevel@tonic-gate ohci_handle_clrchng_port_over_current(
10190Sstevel@tonic-gate ohci_state_t *ohcip,
10200Sstevel@tonic-gate uint16_t port)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate uint_t port_status;
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate port_status = Get_OpReg(hcr_rh_portstatus[port]);
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10290Sstevel@tonic-gate "ohci_handle_clrchng_port_over_current: port = 0x%x"
10300Sstevel@tonic-gate "status = 0x%x", port, port_status);
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_OCIC);
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate /*
10390Sstevel@tonic-gate * ohci_handle_get_port_status:
10400Sstevel@tonic-gate *
10410Sstevel@tonic-gate * Handle a get port status request.
10420Sstevel@tonic-gate */
10430Sstevel@tonic-gate static void
ohci_handle_get_port_status(ohci_state_t * ohcip,uint16_t port)10440Sstevel@tonic-gate ohci_handle_get_port_status(
10450Sstevel@tonic-gate ohci_state_t *ohcip,
10460Sstevel@tonic-gate uint16_t port)
10470Sstevel@tonic-gate {
10480Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
10490Sstevel@tonic-gate mblk_t *message;
10500Sstevel@tonic-gate uint_t new_port_status;
10510Sstevel@tonic-gate uint_t change_status;
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate /* Read the current port status and return it */
10580Sstevel@tonic-gate new_port_status = Get_OpReg(hcr_rh_portstatus[port]);
10590Sstevel@tonic-gate ohcip->ohci_root_hub.rh_port_status[port] = new_port_status;
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate change_status = (new_port_status & HCR_PORT_CHNG_MASK) >> 16;
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10640Sstevel@tonic-gate "ohci_handle_get_port_status: port = %d new status = 0x%x"
10650Sstevel@tonic-gate "change = 0x%x", port, new_port_status, change_status);
10660Sstevel@tonic-gate
10670Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate ASSERT(message != NULL);
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)new_port_status;
10720Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_port_status >> 8);
10730Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)change_status;
10740Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(change_status >> 8);
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate /* Save the data in control request */
10770Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
10780Sstevel@tonic-gate
10790Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate /*
10842326Ssl147100 * ohci_handle_set_clear_hub_feature:
10852326Ssl147100 *
10862326Ssl147100 * OHCI only implements clearing C_HUB_OVER_CURRENT feature now.
10872326Ssl147100 * Other hub requests of this bmRequestType are either not
10882326Ssl147100 * supported by hardware or never used.
10892326Ssl147100 */
10902326Ssl147100 static int
ohci_handle_set_clear_hub_feature(ohci_state_t * ohcip,uchar_t bRequest,uint16_t wValue)10912326Ssl147100 ohci_handle_set_clear_hub_feature(
10922326Ssl147100 ohci_state_t *ohcip,
10932326Ssl147100 uchar_t bRequest,
10942326Ssl147100 uint16_t wValue)
10952326Ssl147100 {
10962326Ssl147100 int error = USB_SUCCESS;
10972326Ssl147100
10982326Ssl147100 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
10992326Ssl147100 "ohci_handle_set_clear_hub_feature: 0x%x 0x%x",
11002326Ssl147100 bRequest, wValue);
11012326Ssl147100
11022326Ssl147100 switch (bRequest) {
11032326Ssl147100 case USB_REQ_CLEAR_FEATURE:
11042326Ssl147100 if (wValue == CFS_C_HUB_OVER_CURRENT) {
11052326Ssl147100 ohci_handle_clrchng_hub_over_current(ohcip);
11062326Ssl147100 } else {
11072326Ssl147100 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11082326Ssl147100 "ohci_handle_set_clear_hub_feature: "
11092326Ssl147100 "Unsupported request 0x%x 0x%x", bRequest, wValue);
11102326Ssl147100
11112326Ssl147100 error = USB_FAILURE;
11122326Ssl147100 }
11132326Ssl147100 break;
11142326Ssl147100
11152326Ssl147100 case USB_REQ_SET_FEATURE:
11162326Ssl147100 default:
11172326Ssl147100 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11182326Ssl147100 "ohci_handle_set_clear_hub_feature: "
11192326Ssl147100 "Unsupported request 0x%x 0x%x", bRequest, wValue);
11202326Ssl147100
11212326Ssl147100 error = USB_FAILURE;
11222326Ssl147100 break;
11232326Ssl147100 }
11242326Ssl147100
11252326Ssl147100 return (error);
11262326Ssl147100 }
11272326Ssl147100
11282326Ssl147100
11292326Ssl147100 /*
11302326Ssl147100 * ohci_handle_clrchng_hub_over_current:
11312326Ssl147100 *
11322326Ssl147100 * Clear over current indicator change bit on the root hub.
11332326Ssl147100 */
11342326Ssl147100 static void
ohci_handle_clrchng_hub_over_current(ohci_state_t * ohcip)11352326Ssl147100 ohci_handle_clrchng_hub_over_current(
11362326Ssl147100 ohci_state_t *ohcip)
11372326Ssl147100 {
11382326Ssl147100 uint_t hub_status;
11392326Ssl147100
11402326Ssl147100 mutex_enter(&ohcip->ohci_int_mutex);
11412326Ssl147100
11422326Ssl147100 hub_status = Get_OpReg(hcr_rh_status);
11432326Ssl147100
11442326Ssl147100 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11452326Ssl147100 "ohci_handle_clrchng_hub_over_current: "
11462326Ssl147100 "status = 0x%x", hub_status);
11472326Ssl147100
11482326Ssl147100 Set_OpReg(hcr_rh_status, HCR_RH_STATUS_OCIC);
11492326Ssl147100
11502326Ssl147100 mutex_exit(&ohcip->ohci_int_mutex);
11512326Ssl147100 }
11522326Ssl147100
11532326Ssl147100
11542326Ssl147100 /*
11550Sstevel@tonic-gate * ohci_handle_get_hub_descriptor:
11560Sstevel@tonic-gate */
11570Sstevel@tonic-gate static void
ohci_handle_get_hub_descriptor(ohci_state_t * ohcip)11580Sstevel@tonic-gate ohci_handle_get_hub_descriptor(
11590Sstevel@tonic-gate ohci_state_t *ohcip)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
11620Sstevel@tonic-gate mblk_t *message;
11630Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr;
11640Sstevel@tonic-gate size_t length;
11650Sstevel@tonic-gate uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
11660Sstevel@tonic-gate
11670Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
11700Sstevel@tonic-gate root_hub_descr = &ohcip->ohci_root_hub.rh_descr;
11710Sstevel@tonic-gate length = ctrl_reqp->ctrl_wLength;
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
11740Sstevel@tonic-gate "ohci_handle_get_hub_descriptor: Ctrl Req = 0x%p",
1175*6898Sfb209375 (void *)ctrl_reqp);
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate ASSERT(message != NULL);
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate raw_descr[0] = root_hub_descr->bDescLength;
11840Sstevel@tonic-gate raw_descr[1] = root_hub_descr->bDescriptorType;
11850Sstevel@tonic-gate raw_descr[2] = root_hub_descr->bNbrPorts;
11860Sstevel@tonic-gate raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF;
11870Sstevel@tonic-gate raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8;
11880Sstevel@tonic-gate raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
11890Sstevel@tonic-gate raw_descr[6] = root_hub_descr->bHubContrCurrent;
11900Sstevel@tonic-gate raw_descr[7] = root_hub_descr->DeviceRemovable;
11910Sstevel@tonic-gate raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate bcopy(raw_descr, message->b_wptr, length);
11940Sstevel@tonic-gate message->b_wptr += length;
11950Sstevel@tonic-gate
11960Sstevel@tonic-gate /* Save the data in control request */
11970Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
11980Sstevel@tonic-gate
11990Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate * ohci_handle_get_hub_status:
12050Sstevel@tonic-gate *
12060Sstevel@tonic-gate * Handle a get hub status request.
12070Sstevel@tonic-gate */
12080Sstevel@tonic-gate static void
ohci_handle_get_hub_status(ohci_state_t * ohcip)12090Sstevel@tonic-gate ohci_handle_get_hub_status(
12100Sstevel@tonic-gate ohci_state_t *ohcip)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp;
12130Sstevel@tonic-gate mblk_t *message;
12140Sstevel@tonic-gate uint_t new_root_hub_status;
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
12190Sstevel@tonic-gate new_root_hub_status = Get_OpReg(hcr_rh_status);
12200Sstevel@tonic-gate
12210Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
12220Sstevel@tonic-gate "ohci_handle_get_hub_status: new root hub status = 0x%x",
12230Sstevel@tonic-gate new_root_hub_status);
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate message = ctrl_reqp->ctrl_data;
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate ASSERT(message != NULL);
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)new_root_hub_status;
12300Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8);
12310Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16);
12320Sstevel@tonic-gate *message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24);
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate /* Save the data in control request */
12350Sstevel@tonic-gate ctrl_reqp->ctrl_data = message;
12360Sstevel@tonic-gate
12370Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate /*
12421001Ssl147100 * ohci_handle_get_device_status:
12431001Ssl147100 *
12441001Ssl147100 * Handle a get device status request.
12451001Ssl147100 */
12461001Ssl147100 static void
ohci_handle_get_device_status(ohci_state_t * ohcip)12471001Ssl147100 ohci_handle_get_device_status(
12481001Ssl147100 ohci_state_t *ohcip)
12491001Ssl147100 {
12501001Ssl147100 usb_ctrl_req_t *ctrl_reqp;
12511001Ssl147100 mblk_t *message;
12521001Ssl147100 uint16_t dev_status;
12531001Ssl147100
12541001Ssl147100 mutex_enter(&ohcip->ohci_int_mutex);
12551001Ssl147100
12561001Ssl147100 ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
12571001Ssl147100
12581001Ssl147100 /*
12591001Ssl147100 * OHCI doesn't have device status information.
12601001Ssl147100 * Simply return what is desired for the request.
12611001Ssl147100 */
12621001Ssl147100 dev_status = USB_DEV_SLF_PWRD_STATUS;
12631001Ssl147100
12641001Ssl147100 USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
12651001Ssl147100 "ohci_handle_get_device_status: device status = 0x%x",
12661001Ssl147100 dev_status);
12671001Ssl147100
12681001Ssl147100 message = ctrl_reqp->ctrl_data;
12691001Ssl147100
12701001Ssl147100 ASSERT(message != NULL);
12711001Ssl147100
12721001Ssl147100 *message->b_wptr++ = (uchar_t)dev_status;
12731001Ssl147100 *message->b_wptr++ = (uchar_t)(dev_status >> 8);
12741001Ssl147100
12751001Ssl147100 /* Save the data in control request */
12761001Ssl147100 ctrl_reqp->ctrl_data = message;
12771001Ssl147100
12781001Ssl147100 mutex_exit(&ohcip->ohci_int_mutex);
12791001Ssl147100 }
12801001Ssl147100
12811001Ssl147100
12821001Ssl147100 /*
12830Sstevel@tonic-gate * ohci_handle_root_hub_pipe_start_intr_polling:
12840Sstevel@tonic-gate *
12850Sstevel@tonic-gate * Handle start polling on root hub interrupt pipe.
12860Sstevel@tonic-gate */
12870Sstevel@tonic-gate /* ARGSUSED */
12880Sstevel@tonic-gate int
ohci_handle_root_hub_pipe_start_intr_polling(usba_pipe_handle_data_t * ph,usb_intr_req_t * client_intr_reqp,usb_flags_t flags)12890Sstevel@tonic-gate ohci_handle_root_hub_pipe_start_intr_polling(
12900Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
12910Sstevel@tonic-gate usb_intr_req_t *client_intr_reqp,
12920Sstevel@tonic-gate usb_flags_t flags)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
1295*6898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
12960Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
12970Sstevel@tonic-gate int error = USB_SUCCESS;
12980Sstevel@tonic-gate uint_t pipe_state;
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13010Sstevel@tonic-gate "ohci_handle_root_hub_pipe_start_intr_polling: "
13020Sstevel@tonic-gate "Root hub pipe start polling");
13030Sstevel@tonic-gate
13040Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate /* ONE_XFER not supported for root hub interrupt pipe */
13090Sstevel@tonic-gate ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
13100Sstevel@tonic-gate
13110Sstevel@tonic-gate /* Get root hub intr pipe state */
13120Sstevel@tonic-gate pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate switch (pipe_state) {
13150Sstevel@tonic-gate case OHCI_PIPE_STATE_IDLE:
13160Sstevel@tonic-gate ASSERT(ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0);
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate /*
13190Sstevel@tonic-gate * Save the Original Client's Interrupt IN request
13200Sstevel@tonic-gate * information. We use this for final callback
13210Sstevel@tonic-gate */
13220Sstevel@tonic-gate ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp == NULL);
13230Sstevel@tonic-gate
13240Sstevel@tonic-gate ohcip->ohci_root_hub.rh_client_intr_reqp = client_intr_reqp;
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate error = ohci_root_hub_allocate_intr_pipe_resource(ohcip, flags);
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate if (error != USB_SUCCESS) {
13290Sstevel@tonic-gate /* Reset client interrupt request pointer */
13300Sstevel@tonic-gate ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13330Sstevel@tonic-gate "ohci_handle_root_hub_pipe_start_intr_polling: "
13340Sstevel@tonic-gate "No Resources");
13350Sstevel@tonic-gate
13360Sstevel@tonic-gate return (error);
13370Sstevel@tonic-gate }
13380Sstevel@tonic-gate
13390Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13400Sstevel@tonic-gate "ohci_handle_root_hub_pipe_start_intr_polling: "
13410Sstevel@tonic-gate "Start polling for root hub successful");
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate break;
13440Sstevel@tonic-gate case OHCI_PIPE_STATE_ACTIVE:
13450Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13460Sstevel@tonic-gate "ohci_handle_root_hub_pipe_start_intr_polling: "
13470Sstevel@tonic-gate "Polling for root hub is already in progress");
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate break;
13500Sstevel@tonic-gate default:
13510Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13520Sstevel@tonic-gate "ohci_handle_root_hub_pipe_start_intr_polling: "
13530Sstevel@tonic-gate "Pipe is in error state 0x%x", pipe_state);
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate error = USB_FAILURE;
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate break;
13580Sstevel@tonic-gate }
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate return (error);
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate
13630Sstevel@tonic-gate
13640Sstevel@tonic-gate /*
13650Sstevel@tonic-gate * ohci_handle_root_hub_pipe_stop_intr_polling:
13660Sstevel@tonic-gate *
13670Sstevel@tonic-gate * Handle stop polling on root hub intr pipe.
13680Sstevel@tonic-gate */
13690Sstevel@tonic-gate /* ARGSUSED */
13700Sstevel@tonic-gate void
ohci_handle_root_hub_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)13710Sstevel@tonic-gate ohci_handle_root_hub_pipe_stop_intr_polling(
13720Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
13730Sstevel@tonic-gate usb_flags_t flags)
13740Sstevel@tonic-gate {
13750Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
1376*6898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
13770Sstevel@tonic-gate usb_ep_descr_t *eptd = &ph->p_ep;
13780Sstevel@tonic-gate
13790Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13820Sstevel@tonic-gate "ohci_handle_root_hub_pipe_stop_intr_polling: "
13830Sstevel@tonic-gate "Root hub pipe stop polling");
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state =
13900Sstevel@tonic-gate OHCI_PIPE_STATE_STOP_POLLING;
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate /* Do interrupt pipe cleanup */
13930Sstevel@tonic-gate ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_STOPPED_POLLING);
13940Sstevel@tonic-gate
13950Sstevel@tonic-gate ASSERT(ohcip->ohci_root_hub.
13960Sstevel@tonic-gate rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
13990Sstevel@tonic-gate "ohci_hcdi_pipe_stop_intr_polling: Stop polling for root"
14000Sstevel@tonic-gate "hub successful");
14010Sstevel@tonic-gate } else {
14020Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14030Sstevel@tonic-gate "ohci_hcdi_pipe_stop_intr_polling: "
14040Sstevel@tonic-gate "Polling for root hub is already stopped");
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate }
14070Sstevel@tonic-gate
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate /*
14100Sstevel@tonic-gate * ohci_root_hub_allocate_intr_pipe_resource:
14110Sstevel@tonic-gate *
14120Sstevel@tonic-gate * Allocate interrupt requests and initialize them.
14130Sstevel@tonic-gate */
14140Sstevel@tonic-gate static int
ohci_root_hub_allocate_intr_pipe_resource(ohci_state_t * ohcip,usb_flags_t flags)14150Sstevel@tonic-gate ohci_root_hub_allocate_intr_pipe_resource(
14160Sstevel@tonic-gate ohci_state_t *ohcip,
14170Sstevel@tonic-gate usb_flags_t flags)
14180Sstevel@tonic-gate {
14190Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
14200Sstevel@tonic-gate size_t length;
14210Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
14220Sstevel@tonic-gate
14230Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14240Sstevel@tonic-gate "ohci_root_hub_allocate_intr_pipe_resource");
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate /* Get the interrupt pipe handle */
14290Sstevel@tonic-gate ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
14300Sstevel@tonic-gate
14310Sstevel@tonic-gate /* Get the current interrupt request pointer */
14320Sstevel@tonic-gate curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate /*
14350Sstevel@tonic-gate * If current interrupt request pointer is null,
14360Sstevel@tonic-gate * allocate new interrupt request.
14370Sstevel@tonic-gate */
14380Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
14390Sstevel@tonic-gate ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp);
14400Sstevel@tonic-gate
14410Sstevel@tonic-gate /* Get the length of interrupt transfer */
14420Sstevel@tonic-gate length = ohcip->ohci_root_hub.
14430Sstevel@tonic-gate rh_client_intr_reqp->intr_len;
14440Sstevel@tonic-gate
14450Sstevel@tonic-gate curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
14460Sstevel@tonic-gate ohcip->ohci_root_hub.rh_client_intr_reqp,
14470Sstevel@tonic-gate length, flags);
14480Sstevel@tonic-gate
14490Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
14500Sstevel@tonic-gate
14510Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14520Sstevel@tonic-gate "ohci_root_hub_allocate_intr_pipe_resource:"
14530Sstevel@tonic-gate "Interrupt request structure allocation failed");
14540Sstevel@tonic-gate
14550Sstevel@tonic-gate return (USB_NO_RESOURCES);
14560Sstevel@tonic-gate }
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
14610Sstevel@tonic-gate ph->p_req_count++;
14620Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate
14650Sstevel@tonic-gate /* Start the timer for the root hub interrupt pipe polling */
14660Sstevel@tonic-gate if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0) {
14670Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id =
14680Sstevel@tonic-gate timeout(ohci_handle_root_hub_status_change,
14690Sstevel@tonic-gate (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME));
14700Sstevel@tonic-gate
14710Sstevel@tonic-gate ohcip->ohci_root_hub.
14720Sstevel@tonic-gate rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE;
14730Sstevel@tonic-gate }
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate return (USB_SUCCESS);
14760Sstevel@tonic-gate }
14770Sstevel@tonic-gate
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * ohci_root_hub_intr_pipe_cleanup:
14810Sstevel@tonic-gate *
14820Sstevel@tonic-gate * Deallocate all interrupt requests and do callback
14830Sstevel@tonic-gate * the original client interrupt request.
14840Sstevel@tonic-gate */
14850Sstevel@tonic-gate static void
ohci_root_hub_intr_pipe_cleanup(ohci_state_t * ohcip,usb_cr_t completion_reason)14860Sstevel@tonic-gate ohci_root_hub_intr_pipe_cleanup(
14870Sstevel@tonic-gate ohci_state_t *ohcip,
14880Sstevel@tonic-gate usb_cr_t completion_reason)
14890Sstevel@tonic-gate {
14900Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
14910Sstevel@tonic-gate usb_opaque_t client_intr_reqp;
14920Sstevel@tonic-gate timeout_id_t timer_id;
14930Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
14960Sstevel@tonic-gate "ohci_root_hub_intr_pipe_cleanup");
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
14990Sstevel@tonic-gate
15000Sstevel@tonic-gate /* Get the interrupt pipe handle */
15010Sstevel@tonic-gate ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
15020Sstevel@tonic-gate
15030Sstevel@tonic-gate /* Get the interrupt timerid */
15040Sstevel@tonic-gate timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id;
15050Sstevel@tonic-gate
15060Sstevel@tonic-gate /* Stop the root hub interrupt timer */
15070Sstevel@tonic-gate if (timer_id) {
15080Sstevel@tonic-gate /* Reset the timer id to zero */
15090Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
15120Sstevel@tonic-gate (void) untimeout(timer_id);
15130Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate
15160Sstevel@tonic-gate /* Reset the current interrupt request pointer */
15170Sstevel@tonic-gate curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate /* Deallocate uncompleted interrupt request */
15200Sstevel@tonic-gate if (curr_intr_reqp) {
15210Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
15220Sstevel@tonic-gate usb_free_intr_req(curr_intr_reqp);
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
15250Sstevel@tonic-gate ph->p_req_count--;
15260Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate
15290Sstevel@tonic-gate client_intr_reqp = (usb_opaque_t)
15300Sstevel@tonic-gate ohcip->ohci_root_hub.rh_client_intr_reqp;
15310Sstevel@tonic-gate
15320Sstevel@tonic-gate /* Callback for original client interrupt request */
15330Sstevel@tonic-gate if (client_intr_reqp) {
15340Sstevel@tonic-gate ohci_root_hub_hcdi_callback(ph, completion_reason);
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate }
15370Sstevel@tonic-gate
15380Sstevel@tonic-gate
15390Sstevel@tonic-gate /*
15400Sstevel@tonic-gate * ohci_handle_root_hub_status_change:
15410Sstevel@tonic-gate *
15420Sstevel@tonic-gate * A root hub status change interrupt will occur any time there is a change
15430Sstevel@tonic-gate * in the root hub status register or one of the port status registers.
15440Sstevel@tonic-gate */
15450Sstevel@tonic-gate void
ohci_handle_root_hub_status_change(void * arg)15460Sstevel@tonic-gate ohci_handle_root_hub_status_change(void *arg)
15470Sstevel@tonic-gate {
15480Sstevel@tonic-gate ohci_state_t *ohcip = (ohci_state_t *)arg;
15490Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
1550520Shx149380 usb_port_mask_t all_ports_status = 0;
15510Sstevel@tonic-gate uint_t new_root_hub_status;
15520Sstevel@tonic-gate uint_t new_port_status;
15530Sstevel@tonic-gate uint_t change_status;
15540Sstevel@tonic-gate usb_hub_descr_t *hub_descr;
15550Sstevel@tonic-gate mblk_t *message;
15560Sstevel@tonic-gate size_t length;
15570Sstevel@tonic-gate usb_ep_descr_t *eptd;
15580Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
15590Sstevel@tonic-gate int i;
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
15620Sstevel@tonic-gate
15630Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
15640Sstevel@tonic-gate "ohci_handle_root_hub_status_change: state = %d",
15650Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state);
15660Sstevel@tonic-gate
15670Sstevel@tonic-gate /* Get the pointer to root hub descriptor */
15680Sstevel@tonic-gate hub_descr = &ohcip->ohci_root_hub.rh_descr;
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate /* Get the current interrupt request pointer */
15710Sstevel@tonic-gate curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
15720Sstevel@tonic-gate
15730Sstevel@tonic-gate ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate /* Check whether timeout handler is valid */
15760Sstevel@tonic-gate if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id) {
15770Sstevel@tonic-gate /* Check host controller is in operational state */
15780Sstevel@tonic-gate if ((ohci_state_is_operational(ohcip)) != USB_SUCCESS) {
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate /* Reset the timer id */
15810Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
15820Sstevel@tonic-gate
15830Sstevel@tonic-gate /* Do interrupt pipe cleanup */
15840Sstevel@tonic-gate ohci_root_hub_intr_pipe_cleanup(
15850Sstevel@tonic-gate ohcip, USB_CR_HC_HARDWARE_ERR);
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
15880Sstevel@tonic-gate
15890Sstevel@tonic-gate return;
15900Sstevel@tonic-gate }
15910Sstevel@tonic-gate } else {
15920Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
15930Sstevel@tonic-gate
15940Sstevel@tonic-gate return;
15950Sstevel@tonic-gate }
15960Sstevel@tonic-gate
15970Sstevel@tonic-gate eptd = &ohcip->ohci_root_hub.rh_intr_pipe_handle->p_ep;
15980Sstevel@tonic-gate
15990Sstevel@tonic-gate new_root_hub_status = Get_OpReg(hcr_rh_status);
16000Sstevel@tonic-gate
16010Sstevel@tonic-gate /* See if the root hub status has changed */
16022326Ssl147100 if (new_root_hub_status & HCR_RH_CHNG_MASK) {
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
16050Sstevel@tonic-gate "ohci_handle_root_hub_status_change: "
16060Sstevel@tonic-gate "Root hub status has changed!");
16070Sstevel@tonic-gate
16080Sstevel@tonic-gate all_ports_status = 1;
16092326Ssl147100
16102326Ssl147100 /* Update root hub status */
16112326Ssl147100 ohcip->ohci_root_hub.rh_status = new_root_hub_status;
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate
16140Sstevel@tonic-gate /* Check each port */
16150Sstevel@tonic-gate for (i = 0; i < hub_descr->bNbrPorts; i++) {
16160Sstevel@tonic-gate new_port_status = Get_OpReg(hcr_rh_portstatus[i]);
16170Sstevel@tonic-gate change_status = new_port_status & HCR_PORT_CHNG_MASK;
16180Sstevel@tonic-gate
16190Sstevel@tonic-gate /*
16200Sstevel@tonic-gate * If there is change in the port status then set
16210Sstevel@tonic-gate * the bit in the bitmap of changes and inform hub
16220Sstevel@tonic-gate * driver about these changes. Hub driver will take
16230Sstevel@tonic-gate * care of these changes.
16240Sstevel@tonic-gate */
16250Sstevel@tonic-gate if (change_status) {
16260Sstevel@tonic-gate
16270Sstevel@tonic-gate /* See if a device was attached/detached */
16280Sstevel@tonic-gate if (change_status & HCR_PORT_CSC) {
16290Sstevel@tonic-gate /*
16300Sstevel@tonic-gate * Update the state depending on whether
16310Sstevel@tonic-gate * the port was attached or detached.
16320Sstevel@tonic-gate */
16330Sstevel@tonic-gate if (new_port_status & HCR_PORT_CCS) {
16340Sstevel@tonic-gate ohcip->ohci_root_hub.
16350Sstevel@tonic-gate rh_port_state[i] = DISABLED;
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16380Sstevel@tonic-gate ohcip->ohci_log_hdl,
1639520Shx149380 "Port %d connected", i+1);
16400Sstevel@tonic-gate } else {
16410Sstevel@tonic-gate ohcip->ohci_root_hub.
16420Sstevel@tonic-gate rh_port_state[i] = DISCONNECTED;
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16450Sstevel@tonic-gate ohcip->ohci_log_hdl,
1646520Shx149380 "Port %d disconnected", i+1);
16470Sstevel@tonic-gate }
16480Sstevel@tonic-gate }
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate /* See if port enable status changed */
16510Sstevel@tonic-gate if (change_status & HCR_PORT_PESC) {
16520Sstevel@tonic-gate /*
16530Sstevel@tonic-gate * Update the state depending on whether
16540Sstevel@tonic-gate * the port was enabled or disabled.
16550Sstevel@tonic-gate */
16560Sstevel@tonic-gate if (new_port_status & HCR_PORT_PES) {
16570Sstevel@tonic-gate ohcip->ohci_root_hub.
16580Sstevel@tonic-gate rh_port_state[i] = ENABLED;
16590Sstevel@tonic-gate
16600Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16610Sstevel@tonic-gate ohcip->ohci_log_hdl,
1662520Shx149380 "Port %d enabled", i+1);
16630Sstevel@tonic-gate } else {
16640Sstevel@tonic-gate ohcip->ohci_root_hub.
16650Sstevel@tonic-gate rh_port_state[i] = DISABLED;
16660Sstevel@tonic-gate
16670Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
16680Sstevel@tonic-gate ohcip->ohci_log_hdl,
1669520Shx149380 "Port %d disabled", i+1);
16700Sstevel@tonic-gate }
16710Sstevel@tonic-gate }
16720Sstevel@tonic-gate
16730Sstevel@tonic-gate all_ports_status |= 1 << (i + 1);
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate /* Update the status */
16760Sstevel@tonic-gate ohcip->ohci_root_hub.
16770Sstevel@tonic-gate rh_port_status[i] = new_port_status;
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate }
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate if (ph && all_ports_status && curr_intr_reqp) {
16820Sstevel@tonic-gate
16830Sstevel@tonic-gate length = eptd->wMaxPacketSize;
16840Sstevel@tonic-gate
16850Sstevel@tonic-gate ASSERT(length != 0);
16860Sstevel@tonic-gate
16870Sstevel@tonic-gate /* Get the message block */
16880Sstevel@tonic-gate message = curr_intr_reqp->intr_data;
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate ASSERT(message != NULL);
16910Sstevel@tonic-gate
1692520Shx149380 do {
1693520Shx149380 /*
1694520Shx149380 * check that mblk is big enough when we
1695520Shx149380 * are writing bytes into it
1696520Shx149380 */
1697520Shx149380 if (message->b_wptr >= message->b_datap->db_lim) {
1698520Shx149380
1699520Shx149380 USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
1700520Shx149380 ohcip->ohci_log_hdl,
1701520Shx149380 "ohci_handle_root_hub_status_change: "
1702520Shx149380 "mblk data overflow.");
1703520Shx149380
1704520Shx149380 break;
1705520Shx149380 }
1706520Shx149380
1707520Shx149380 *message->b_wptr++ = (uchar_t)all_ports_status;
1708520Shx149380 all_ports_status >>= 8;
1709520Shx149380 } while (all_ports_status != 0);
17100Sstevel@tonic-gate
17110Sstevel@tonic-gate ohci_root_hub_hcdi_callback(ph, USB_CR_OK);
17120Sstevel@tonic-gate }
17130Sstevel@tonic-gate
17140Sstevel@tonic-gate /* Reset the timer id */
17150Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
17180Sstevel@tonic-gate /*
17190Sstevel@tonic-gate * If needed, allocate new interrupt request. Also
17200Sstevel@tonic-gate * start the timer for the root hub interrupt polling.
17210Sstevel@tonic-gate */
17220Sstevel@tonic-gate if ((ohci_root_hub_allocate_intr_pipe_resource(
17230Sstevel@tonic-gate ohcip, 0)) != USB_SUCCESS) {
17240Sstevel@tonic-gate
17250Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
17260Sstevel@tonic-gate "ohci_handle_root_hub_status_change: No Resources");
17270Sstevel@tonic-gate
17280Sstevel@tonic-gate /* Do interrupt pipe cleanup */
17290Sstevel@tonic-gate ohci_root_hub_intr_pipe_cleanup(
17300Sstevel@tonic-gate ohcip, USB_CR_NO_RESOURCES);
17310Sstevel@tonic-gate }
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate
17340Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate
17380Sstevel@tonic-gate /*
17390Sstevel@tonic-gate * ohci_root_hub_hcdi_callback()
17400Sstevel@tonic-gate *
17410Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() for the root hub.
17420Sstevel@tonic-gate */
17430Sstevel@tonic-gate static void
ohci_root_hub_hcdi_callback(usba_pipe_handle_data_t * ph,usb_cr_t completion_reason)17440Sstevel@tonic-gate ohci_root_hub_hcdi_callback(
17450Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
17460Sstevel@tonic-gate usb_cr_t completion_reason)
17470Sstevel@tonic-gate {
17480Sstevel@tonic-gate ohci_state_t *ohcip = ohci_obtain_state(
1749*6898Sfb209375 ph->p_usba_device->usb_root_hub_dip);
17500Sstevel@tonic-gate uchar_t attributes = ph->p_ep.bmAttributes &
1751*6898Sfb209375 USB_EP_ATTR_MASK;
17520Sstevel@tonic-gate usb_opaque_t curr_xfer_reqp;
17530Sstevel@tonic-gate uint_t pipe_state = 0;
17540Sstevel@tonic-gate
17550Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
17560Sstevel@tonic-gate "ohci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
1757*6898Sfb209375 (void *)ph, completion_reason);
17580Sstevel@tonic-gate
17590Sstevel@tonic-gate ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate /* Set the pipe state as per completion reason */
17620Sstevel@tonic-gate switch (completion_reason) {
17630Sstevel@tonic-gate case USB_CR_OK:
17640Sstevel@tonic-gate switch (attributes) {
17650Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
17660Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_IDLE;
17670Sstevel@tonic-gate break;
17680Sstevel@tonic-gate case USB_EP_ATTR_INTR:
17690Sstevel@tonic-gate pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
17700Sstevel@tonic-gate break;
17710Sstevel@tonic-gate }
17720Sstevel@tonic-gate break;
17730Sstevel@tonic-gate case USB_CR_NO_RESOURCES:
17740Sstevel@tonic-gate case USB_CR_NOT_SUPPORTED:
17750Sstevel@tonic-gate case USB_CR_STOPPED_POLLING:
17760Sstevel@tonic-gate case USB_CR_PIPE_RESET:
17770Sstevel@tonic-gate case USB_CR_HC_HARDWARE_ERR:
17780Sstevel@tonic-gate /* Set pipe state to idle */
17790Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_IDLE;
17800Sstevel@tonic-gate break;
17810Sstevel@tonic-gate case USB_CR_PIPE_CLOSING:
17820Sstevel@tonic-gate break;
17830Sstevel@tonic-gate default:
17840Sstevel@tonic-gate /* Set pipe state to error */
17850Sstevel@tonic-gate pipe_state = OHCI_PIPE_STATE_ERROR;
17860Sstevel@tonic-gate break;
17870Sstevel@tonic-gate }
17880Sstevel@tonic-gate
17890Sstevel@tonic-gate switch (attributes) {
17900Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
17910Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)
17920Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
17930Sstevel@tonic-gate
17940Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
17950Sstevel@tonic-gate ohcip->ohci_root_hub.rh_ctrl_pipe_state = pipe_state;
17960Sstevel@tonic-gate break;
17970Sstevel@tonic-gate case USB_EP_ATTR_INTR:
17980Sstevel@tonic-gate /* if curr_intr_reqp available then use this request */
17990Sstevel@tonic-gate if (ohcip->ohci_root_hub.rh_curr_intr_reqp) {
18000Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)
18010Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_intr_reqp;
18020Sstevel@tonic-gate
18030Sstevel@tonic-gate ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
18040Sstevel@tonic-gate } else {
18050Sstevel@tonic-gate /* no current request, use client's request */
18060Sstevel@tonic-gate curr_xfer_reqp = (usb_opaque_t)
18070Sstevel@tonic-gate ohcip->ohci_root_hub.rh_client_intr_reqp;
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
18100Sstevel@tonic-gate }
18110Sstevel@tonic-gate
18120Sstevel@tonic-gate ohcip->ohci_root_hub.rh_intr_pipe_state = pipe_state;
18130Sstevel@tonic-gate break;
18140Sstevel@tonic-gate }
18150Sstevel@tonic-gate
18160Sstevel@tonic-gate ASSERT(curr_xfer_reqp != NULL);
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate mutex_exit(&ohcip->ohci_int_mutex);
18190Sstevel@tonic-gate usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
18200Sstevel@tonic-gate mutex_enter(&ohcip->ohci_int_mutex);
18210Sstevel@tonic-gate }
1822