17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5112116d8Sfb * Common Development and Distribution License (the "License").
6112116d8Sfb * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22112116d8Sfb * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * Universal Serial BUS Host Controller Driver (UHCI)
297c478bd9Sstevel@tonic-gate *
307c478bd9Sstevel@tonic-gate * The UHCI driver is a driver which interfaces to the Universal
317c478bd9Sstevel@tonic-gate * Serial Bus Architecture (USBA) and the Host Controller (HC). The interface to
327c478bd9Sstevel@tonic-gate * the Host Controller is defined by the Universal Host Controller Interface.
337c478bd9Sstevel@tonic-gate * This file contains the code for root hub related functions.
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcid.h>
367c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhci.h>
377c478bd9Sstevel@tonic-gate #include <sys/usb/hcd/uhci/uhcihub.h>
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate * Function Prototypes
417c478bd9Sstevel@tonic-gate */
427c478bd9Sstevel@tonic-gate static int uhci_handle_set_clear_port_feature(
437c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
447c478bd9Sstevel@tonic-gate uchar_t bRequest,
457c478bd9Sstevel@tonic-gate uint16_t wValue,
467c478bd9Sstevel@tonic-gate usb_port_t port);
477c478bd9Sstevel@tonic-gate static void uhci_handle_port_power(
487c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
497c478bd9Sstevel@tonic-gate usb_port_t port,
507c478bd9Sstevel@tonic-gate uint_t on);
517c478bd9Sstevel@tonic-gate static void uhci_handle_port_suspend(
527c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
537c478bd9Sstevel@tonic-gate usb_port_t port,
547c478bd9Sstevel@tonic-gate uint_t on);
557c478bd9Sstevel@tonic-gate static void uhci_handle_port_enable_disable(
567c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
577c478bd9Sstevel@tonic-gate usb_port_t port,
587c478bd9Sstevel@tonic-gate uint_t on);
597c478bd9Sstevel@tonic-gate static void uhci_handle_port_reset(
607c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
617c478bd9Sstevel@tonic-gate usb_port_t port);
627c478bd9Sstevel@tonic-gate static void uhci_handle_complete_port_reset(
637c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
647c478bd9Sstevel@tonic-gate usb_port_t port);
657c478bd9Sstevel@tonic-gate static void uhci_handle_clear_port_connection(
667c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
677c478bd9Sstevel@tonic-gate usb_port_t port);
687c478bd9Sstevel@tonic-gate static void uhci_handle_get_port_status(
697c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
707c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req,
717c478bd9Sstevel@tonic-gate usb_port_t port);
727c478bd9Sstevel@tonic-gate static void uhci_handle_get_hub_descriptor(
737c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
747c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req);
757c478bd9Sstevel@tonic-gate static void uhci_handle_get_hub_status(
767c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
777c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req);
7835f36846Ssl static void uhci_handle_get_device_status(
7935f36846Ssl uhci_state_t *uhcip,
8035f36846Ssl usb_ctrl_req_t *req);
817c478bd9Sstevel@tonic-gate static uint_t uhci_get_port_status(
827c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
837c478bd9Sstevel@tonic-gate usb_port_t port);
847c478bd9Sstevel@tonic-gate static void uhci_rh_hcdi_callback(
857c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
867c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
877c478bd9Sstevel@tonic-gate usb_opaque_t req,
887c478bd9Sstevel@tonic-gate usb_cr_t cr);
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate * root hub device descriptor
927c478bd9Sstevel@tonic-gate */
937c478bd9Sstevel@tonic-gate static usb_dev_descr_t uhci_rh_dev_descr = {
947c478bd9Sstevel@tonic-gate 0x12, /* Length */
957c478bd9Sstevel@tonic-gate 1, /* Type */
967c478bd9Sstevel@tonic-gate 0x110, /* BCD - v1.1 */
977c478bd9Sstevel@tonic-gate 9, /* Class */
987c478bd9Sstevel@tonic-gate 0, /* Sub class */
997c478bd9Sstevel@tonic-gate 0, /* Protocol */
1007c478bd9Sstevel@tonic-gate 8, /* Max pkt size */
1017c478bd9Sstevel@tonic-gate 0, /* Vendor */
1027c478bd9Sstevel@tonic-gate 0, /* Product id */
1037c478bd9Sstevel@tonic-gate 0, /* Device release */
1047c478bd9Sstevel@tonic-gate 0, /* Manufacturer */
1057c478bd9Sstevel@tonic-gate 0, /* Product */
1067c478bd9Sstevel@tonic-gate 0, /* Sn */
1077c478bd9Sstevel@tonic-gate 1 /* No of configs */
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate * root hub config descriptor
1127c478bd9Sstevel@tonic-gate */
1137c478bd9Sstevel@tonic-gate static uchar_t uhci_rh_config_descr[] = {
1147c478bd9Sstevel@tonic-gate /* config descriptor */
1157c478bd9Sstevel@tonic-gate 0x09, /* bLength */
1167c478bd9Sstevel@tonic-gate 0x02, /* bDescriptorType, Configuration */
1177c478bd9Sstevel@tonic-gate 0x19, 0x00, /* wTotalLength */
1187c478bd9Sstevel@tonic-gate 0x01, /* bNumInterfaces */
1197c478bd9Sstevel@tonic-gate 0x01, /* bConfigurationValue */
1207c478bd9Sstevel@tonic-gate 0x00, /* iConfiguration */
1217c478bd9Sstevel@tonic-gate 0x40, /* bmAttributes */
1227c478bd9Sstevel@tonic-gate 0x00, /* MaxPower */
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate /* interface descriptor */
1257c478bd9Sstevel@tonic-gate 0x09, /* bLength */
1267c478bd9Sstevel@tonic-gate 0x04, /* bDescriptorType, Interface */
1277c478bd9Sstevel@tonic-gate 0x00, /* bInterfaceNumber */
1287c478bd9Sstevel@tonic-gate 0x00, /* bAlternateSetting */
1297c478bd9Sstevel@tonic-gate 0x01, /* bNumEndpoints */
1307c478bd9Sstevel@tonic-gate 0x09, /* bInterfaceClass */
1317c478bd9Sstevel@tonic-gate 0x01, /* bInterfaceSubClass */
1327c478bd9Sstevel@tonic-gate 0x00, /* bInterfaceProtocol */
1337c478bd9Sstevel@tonic-gate 0x00, /* iInterface */
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate /* endpoint descriptor */
1367c478bd9Sstevel@tonic-gate 0x07, /* bLength */
1377c478bd9Sstevel@tonic-gate 0x05, /* bDescriptorType, Endpoint */
1387c478bd9Sstevel@tonic-gate 0x81, /* bEndpointAddress */
1397c478bd9Sstevel@tonic-gate 0x03, /* bmAttributes */
1407c478bd9Sstevel@tonic-gate 0x01, 0x00, /* wMaxPacketSize, 1 + (OHCI_MAX_RH_PORTS / 8) */
1417c478bd9Sstevel@tonic-gate 0x20 /* bInterval */
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate * uhci_init_root_hub:
1477c478bd9Sstevel@tonic-gate * Initialize the root hub
1487c478bd9Sstevel@tonic-gate */
1497c478bd9Sstevel@tonic-gate int
uhci_init_root_hub(uhci_state_t * uhcip)1507c478bd9Sstevel@tonic-gate uhci_init_root_hub(uhci_state_t *uhcip)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate int i, length;
1537c478bd9Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr = &uhcip->uhci_root_hub.rh_descr;
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
1567c478bd9Sstevel@tonic-gate "uhci_init_root_hub:");
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_num_ports = MAX_RH_PORTS;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate * Build the hub descriptor
1627c478bd9Sstevel@tonic-gate */
1637c478bd9Sstevel@tonic-gate root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
1647c478bd9Sstevel@tonic-gate root_hub_descr->bNbrPorts = MAX_RH_PORTS;
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate length = root_hub_descr->bNbrPorts / 8;
1677c478bd9Sstevel@tonic-gate if (length) {
1687c478bd9Sstevel@tonic-gate root_hub_descr->bDescLength = 7 + (2 * (length + 1));
1697c478bd9Sstevel@tonic-gate } else {
1707c478bd9Sstevel@tonic-gate root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /* Determine the Power Switching Mode */
1747c478bd9Sstevel@tonic-gate root_hub_descr->bPwrOn2PwrGood = 10; /* arbitrary number */
1757c478bd9Sstevel@tonic-gate root_hub_descr->wHubCharacteristics =
176112116d8Sfb HUB_CHARS_NO_POWER_SWITCHING|HUB_CHARS_NO_OVER_CURRENT;
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate /* Indicate if the device is removable */
1797c478bd9Sstevel@tonic-gate root_hub_descr->DeviceRemovable = 0x0;
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /* Fill in the port power control mask */
1827c478bd9Sstevel@tonic-gate root_hub_descr->PortPwrCtrlMask = 0xff;
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate for (i = 0; i < uhcip->uhci_root_hub.rh_num_ports; i++) {
1857c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_state[i] = DISCONNECTED;
1867c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_status[i] = 0;
1877c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_changes[i] = 0;
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate /* Finally load the root hub driver */
1917c478bd9Sstevel@tonic-gate return (usba_hubdi_bind_root_hub(uhcip->uhci_dip, uhci_rh_config_descr,
1927c478bd9Sstevel@tonic-gate sizeof (uhci_rh_config_descr), &uhci_rh_dev_descr));
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate * uhci_handle_root_hub_request:
1987c478bd9Sstevel@tonic-gate * Intercept a root hub request.
1997c478bd9Sstevel@tonic-gate * Handle the root hub request through the registers
2007c478bd9Sstevel@tonic-gate */
2017c478bd9Sstevel@tonic-gate int
uhci_handle_root_hub_request(uhci_state_t * uhcip,usba_pipe_handle_data_t * pipe_handle,usb_ctrl_req_t * req)2027c478bd9Sstevel@tonic-gate uhci_handle_root_hub_request(
2037c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
2047c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *pipe_handle,
2057c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
2087c478bd9Sstevel@tonic-gate uint16_t port = req->ctrl_wIndex - 1;
2097c478bd9Sstevel@tonic-gate usb_cr_t completion_reason;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
2127c478bd9Sstevel@tonic-gate "uhci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
2137c478bd9Sstevel@tonic-gate req->ctrl_bmRequestType, req->ctrl_bRequest, req->ctrl_wValue,
2147c478bd9Sstevel@tonic-gate req->ctrl_wIndex, req->ctrl_wLength, (void *)req->ctrl_data);
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate switch (req->ctrl_bmRequestType) {
21935f36846Ssl case HUB_GET_DEVICE_STATUS_TYPE:
22035f36846Ssl uhci_handle_get_device_status(uhcip, req);
22135f36846Ssl
22235f36846Ssl break;
22335f36846Ssl case HUB_HANDLE_PORT_FEATURE_TYPE:
2247c478bd9Sstevel@tonic-gate error = uhci_handle_set_clear_port_feature(uhcip,
2257c478bd9Sstevel@tonic-gate req->ctrl_bRequest, req->ctrl_wValue, port);
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate break;
22835f36846Ssl case HUB_GET_PORT_STATUS_TYPE:
2297c478bd9Sstevel@tonic-gate uhci_handle_get_port_status(uhcip, req, port);
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate break;
23235f36846Ssl case HUB_CLASS_REQ_TYPE:
2337c478bd9Sstevel@tonic-gate switch (req->ctrl_bRequest) {
2347c478bd9Sstevel@tonic-gate case USB_REQ_GET_DESCR:
2357c478bd9Sstevel@tonic-gate uhci_handle_get_hub_descriptor(uhcip, req);
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate break;
2387c478bd9Sstevel@tonic-gate case USB_REQ_GET_STATUS:
2397c478bd9Sstevel@tonic-gate uhci_handle_get_hub_status(uhcip, req);
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate break;
2427c478bd9Sstevel@tonic-gate default:
2437c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
2447c478bd9Sstevel@tonic-gate "uhci_handle_root_hub_request: Unsupported "
2457c478bd9Sstevel@tonic-gate "request 0x%x", req->ctrl_bmRequestType);
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate break;
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate break;
2517c478bd9Sstevel@tonic-gate default:
2527c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
2537c478bd9Sstevel@tonic-gate "uhci_handle_root_hub_request: Unsupported request 0x%x",
2547c478bd9Sstevel@tonic-gate req->ctrl_bmRequestType);
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate break;
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate completion_reason = (error != USB_SUCCESS) ?
260112116d8Sfb USB_CR_NOT_SUPPORTED : USB_CR_OK;
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
2637c478bd9Sstevel@tonic-gate "uhci_handle_root_hub_request: error = %d", error);
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate uhci_rh_hcdi_callback(uhcip, pipe_handle, (usb_opaque_t)req,
266112116d8Sfb completion_reason);
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate * uhci_handle_set_clear_port_feature:
2747c478bd9Sstevel@tonic-gate */
2757c478bd9Sstevel@tonic-gate static int
uhci_handle_set_clear_port_feature(uhci_state_t * uhcip,uchar_t bRequest,uint16_t wValue,usb_port_t port)2767c478bd9Sstevel@tonic-gate uhci_handle_set_clear_port_feature(
2777c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
2787c478bd9Sstevel@tonic-gate uchar_t bRequest,
2797c478bd9Sstevel@tonic-gate uint16_t wValue,
2807c478bd9Sstevel@tonic-gate usb_port_t port)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate int error = USB_SUCCESS;
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
2857c478bd9Sstevel@tonic-gate "uhci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
2867c478bd9Sstevel@tonic-gate bRequest, wValue, port);
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate switch (bRequest) {
2897c478bd9Sstevel@tonic-gate case USB_REQ_SET_FEATURE:
2907c478bd9Sstevel@tonic-gate switch (wValue) {
2917c478bd9Sstevel@tonic-gate case CFS_PORT_ENABLE:
2927c478bd9Sstevel@tonic-gate uhci_handle_port_enable_disable(uhcip,
293112116d8Sfb port, UHCI_ENABLE_PORT);
2947c478bd9Sstevel@tonic-gate break;
2957c478bd9Sstevel@tonic-gate case CFS_PORT_SUSPEND:
2967c478bd9Sstevel@tonic-gate uhci_handle_port_suspend(uhcip, port, 1);
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate break;
2997c478bd9Sstevel@tonic-gate case CFS_PORT_RESET:
3007c478bd9Sstevel@tonic-gate uhci_handle_port_reset(uhcip, port);
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate break;
3037c478bd9Sstevel@tonic-gate case CFS_PORT_POWER:
3047c478bd9Sstevel@tonic-gate uhci_handle_port_power(uhcip, port,
305112116d8Sfb UHCI_ENABLE_PORT_PWR);
3067c478bd9Sstevel@tonic-gate break;
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate default:
309d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
3107c478bd9Sstevel@tonic-gate "uhci_handle_set_clear_port_feature: "
3117c478bd9Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
3127c478bd9Sstevel@tonic-gate error = USB_FAILURE;
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate break;
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate break;
3187c478bd9Sstevel@tonic-gate case USB_REQ_CLEAR_FEATURE:
3197c478bd9Sstevel@tonic-gate switch (wValue) {
3207c478bd9Sstevel@tonic-gate case CFS_PORT_ENABLE:
3217c478bd9Sstevel@tonic-gate uhci_handle_port_enable_disable(uhcip,
322112116d8Sfb port, UHCI_DISABLE_PORT);
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate break;
3257c478bd9Sstevel@tonic-gate case CFS_C_PORT_ENABLE:
3267c478bd9Sstevel@tonic-gate uhci_handle_port_enable_disable(uhcip,
327112116d8Sfb port, UHCI_CLEAR_ENDIS_BIT);
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate break;
3307c478bd9Sstevel@tonic-gate case CFS_PORT_SUSPEND:
3317c478bd9Sstevel@tonic-gate uhci_handle_port_suspend(uhcip, port, 0);
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate break;
3347c478bd9Sstevel@tonic-gate case CFS_C_PORT_RESET:
3357c478bd9Sstevel@tonic-gate uhci_handle_complete_port_reset(uhcip, port);
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate break;
3387c478bd9Sstevel@tonic-gate case CFS_PORT_POWER:
3397c478bd9Sstevel@tonic-gate uhci_handle_port_power(uhcip, port,
340112116d8Sfb UHCI_DISABLE_PORT_PWR);
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate break;
3437c478bd9Sstevel@tonic-gate case CFS_C_PORT_CONNECTION:
3447c478bd9Sstevel@tonic-gate uhci_handle_clear_port_connection(uhcip, port);
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate break;
3477c478bd9Sstevel@tonic-gate default:
348d291d9f2Sfrits USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
3497c478bd9Sstevel@tonic-gate "uhci_handle_set_clear_port_feature: "
3507c478bd9Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
3517c478bd9Sstevel@tonic-gate error = USB_FAILURE;
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate break;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate break;
3577c478bd9Sstevel@tonic-gate default:
3587c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
3597c478bd9Sstevel@tonic-gate "uhci_handle_set_clear_port_feature: "
3607c478bd9Sstevel@tonic-gate "Unsupported request 0x%x 0x%x", bRequest, wValue);
3617c478bd9Sstevel@tonic-gate error = USB_FAILURE;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate return (error);
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate /*
3707c478bd9Sstevel@tonic-gate * uhci_handle_port_suspend:
3717c478bd9Sstevel@tonic-gate */
3727c478bd9Sstevel@tonic-gate static void
uhci_handle_port_suspend(uhci_state_t * uhcip,usb_port_t port,uint_t on)3737c478bd9Sstevel@tonic-gate uhci_handle_port_suspend(
3747c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
3757c478bd9Sstevel@tonic-gate usb_port_t port,
3767c478bd9Sstevel@tonic-gate uint_t on)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate uint_t port_status = Get_OpReg16(PORTSC[port]);
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
3817c478bd9Sstevel@tonic-gate "uhci_handle_port_suspend: port=%d on=%d",
3827c478bd9Sstevel@tonic-gate port, on);
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate if (on) {
3857c478bd9Sstevel@tonic-gate /* See if the port suspend is already on */
3867c478bd9Sstevel@tonic-gate if (!(port_status & HCR_PORT_SUSPEND)) {
3877c478bd9Sstevel@tonic-gate /* suspend the port */
3887c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port],
389112116d8Sfb (port_status | HCR_PORT_SUSPEND));
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate } else {
3927c478bd9Sstevel@tonic-gate /* See if the port suspend is already off */
3937c478bd9Sstevel@tonic-gate if ((port_status & HCR_PORT_SUSPEND)) {
3947c478bd9Sstevel@tonic-gate /* resume the port */
3957c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port],
396112116d8Sfb (port_status & ~HCR_PORT_SUSPEND));
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate * uhci_handle_port_power:
4047c478bd9Sstevel@tonic-gate * Turn on a root hub port. NOTE: Driver does not have any control
4057c478bd9Sstevel@tonic-gate * over the power status.
4067c478bd9Sstevel@tonic-gate */
4077c478bd9Sstevel@tonic-gate /* ARGSUSED */
4087c478bd9Sstevel@tonic-gate static void
uhci_handle_port_power(uhci_state_t * uhcip,usb_port_t port,uint_t on)4097c478bd9Sstevel@tonic-gate uhci_handle_port_power(
4107c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
4117c478bd9Sstevel@tonic-gate usb_port_t port,
4127c478bd9Sstevel@tonic-gate uint_t on)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
4157c478bd9Sstevel@tonic-gate "uhci_handle_port_power: nothing to do");
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate * uhci_handle_port_enable_disable:
4217c478bd9Sstevel@tonic-gate * Handle port enable request.
4227c478bd9Sstevel@tonic-gate */
4237c478bd9Sstevel@tonic-gate static void
uhci_handle_port_enable_disable(uhci_state_t * uhcip,usb_port_t port,uint_t action)4247c478bd9Sstevel@tonic-gate uhci_handle_port_enable_disable(
4257c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
4267c478bd9Sstevel@tonic-gate usb_port_t port,
4277c478bd9Sstevel@tonic-gate uint_t action)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate uint_t port_status = Get_OpReg16(PORTSC[port]);
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
4327c478bd9Sstevel@tonic-gate "uhci_handle_port_enable: port = 0x%x, status = 0x%x",
4337c478bd9Sstevel@tonic-gate port, port_status);
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate if (action == UHCI_ENABLE_PORT) {
4367c478bd9Sstevel@tonic-gate /* See if the port enable is already on */
4377c478bd9Sstevel@tonic-gate if (!(port_status & HCR_PORT_ENABLE)) {
4387c478bd9Sstevel@tonic-gate /* Enable the port */
4397c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port],
440112116d8Sfb (port_status | HCR_PORT_ENABLE));
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate } else if (action == UHCI_DISABLE_PORT) {
4437c478bd9Sstevel@tonic-gate /* See if the port enable is already off */
4447c478bd9Sstevel@tonic-gate if ((port_status & HCR_PORT_ENABLE)) {
4457c478bd9Sstevel@tonic-gate /* Disable the port */
4467c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port],
447112116d8Sfb (port_status & ~HCR_PORT_ENABLE));
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate } else {
4507c478bd9Sstevel@tonic-gate /* Clear the Enable/Disable change bit */
4517c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port], (port_status | HCR_PORT_ENDIS_CHG));
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate /* Update software port_changes register */
4547c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_PESC;
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate * uhci_root_hub_reset_occurred:
4617c478bd9Sstevel@tonic-gate * Inform the upper layer that reset has occured on the port.
4627c478bd9Sstevel@tonic-gate * This is required because the upper layer is expecting an
4637c478bd9Sstevel@tonic-gate * event immediately after doing a reset. In case of OHCI
4647c478bd9Sstevel@tonic-gate * the HC gets an interrupt for the change in the root hub
4657c478bd9Sstevel@tonic-gate * status, but in case of UHCI we don't. So, we send an
4667c478bd9Sstevel@tonic-gate * event to the upper layer as soon as we complete the reset
4677c478bd9Sstevel@tonic-gate * as long as the root hub pipe is polling.
4687c478bd9Sstevel@tonic-gate */
4697c478bd9Sstevel@tonic-gate void
uhci_root_hub_reset_occurred(uhci_state_t * uhcip,uint16_t port)4707c478bd9Sstevel@tonic-gate uhci_root_hub_reset_occurred(
4717c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
4727c478bd9Sstevel@tonic-gate uint16_t port)
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate usb_intr_req_t *intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
4777c478bd9Sstevel@tonic-gate "uhci_root_hub_reset_occurred: intr_reqp = 0x%p data = 0x%p",
478112116d8Sfb (void *)intr_reqp, (void *)intr_reqp->intr_data);
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate *intr_reqp->intr_data->b_wptr++ = (1 << (port+1));
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate uhci_rh_hcdi_callback(uhcip, uhcip->uhci_root_hub.rh_intr_pipe_handle,
4837c478bd9Sstevel@tonic-gate (usb_opaque_t)intr_reqp, USB_CR_OK);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate * uhci_handle_port_reset:
4897c478bd9Sstevel@tonic-gate * Perform a port reset.
4907c478bd9Sstevel@tonic-gate */
4917c478bd9Sstevel@tonic-gate static void
uhci_handle_port_reset(uhci_state_t * uhcip,usb_port_t port)4927c478bd9Sstevel@tonic-gate uhci_handle_port_reset(
4937c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
4947c478bd9Sstevel@tonic-gate usb_port_t port)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate uint_t port_status = Get_OpReg16(PORTSC[port]);
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
4997c478bd9Sstevel@tonic-gate "uhci_handle_port_reset: port = 0x%x, status = 0x%x",
5007c478bd9Sstevel@tonic-gate port, port_status);
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate if (!(port_status & HCR_PORT_CCS)) {
5037c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
5047c478bd9Sstevel@tonic-gate "port_status & HCR_PORT_CCS == 0: "
5057c478bd9Sstevel@tonic-gate "port = 0x%x, status = 0x%x", port, port_status);
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port], (port_status| HCR_PORT_RESET));
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate drv_usecwait(UHCI_RESET_DELAY);
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port], (port_status & ~HCR_PORT_RESET));
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate drv_usecwait(UHCI_RESET_DELAY/100);
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port], (port_status| HCR_PORT_ENABLE));
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate /*
5197c478bd9Sstevel@tonic-gate * The next function is only called if the interrupt pipe
5207c478bd9Sstevel@tonic-gate * is polling and the USBA is ready to receive the
5217c478bd9Sstevel@tonic-gate * data. If not, we could panic.
5227c478bd9Sstevel@tonic-gate */
5237c478bd9Sstevel@tonic-gate if (uhcip->uhci_root_hub.rh_pipe_state != UHCI_PIPE_STATE_ACTIVE) {
5247c478bd9Sstevel@tonic-gate /* make a note that we need to send status back */
5257c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_status = port + 1;
5267c478bd9Sstevel@tonic-gate } else {
5277c478bd9Sstevel@tonic-gate uhci_root_hub_reset_occurred(uhcip, port);
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate * uhci_handle_complete_port_reset:
5347c478bd9Sstevel@tonic-gate * Perform a port reset change.
5357c478bd9Sstevel@tonic-gate */
5367c478bd9Sstevel@tonic-gate static void
uhci_handle_complete_port_reset(uhci_state_t * uhcip,usb_port_t port)5377c478bd9Sstevel@tonic-gate uhci_handle_complete_port_reset(
5387c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
5397c478bd9Sstevel@tonic-gate usb_port_t port)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate uint_t port_status = Get_OpReg16(PORTSC[port]);
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
5447c478bd9Sstevel@tonic-gate "uhci_handle_complete_port_reset: port = 0x%x status = 0x%x",
5457c478bd9Sstevel@tonic-gate port, port_status);
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate if (!(port_status & HCR_PORT_CCS)) {
5487c478bd9Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
5497c478bd9Sstevel@tonic-gate "port_status & HCR_PORT_CCS == 0: "
5507c478bd9Sstevel@tonic-gate "port = 0x%x, status = 0x%x", port, port_status);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port], (port_status & (~ HCR_PORT_RESET)));
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate /* Update software port_changes register */
5567c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_PRSC;
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate /*
5617c478bd9Sstevel@tonic-gate * uhci_handle_clear_port_connection:
5627c478bd9Sstevel@tonic-gate * Perform a clear port connection.
5637c478bd9Sstevel@tonic-gate */
5647c478bd9Sstevel@tonic-gate static void
uhci_handle_clear_port_connection(uhci_state_t * uhcip,usb_port_t port)5657c478bd9Sstevel@tonic-gate uhci_handle_clear_port_connection(
5667c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
5677c478bd9Sstevel@tonic-gate usb_port_t port)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate uint_t port_status = Get_OpReg16(PORTSC[port]);
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
5727c478bd9Sstevel@tonic-gate "uhci_handle_clear_port_connection: port = 0x%x status = 0x%x",
5737c478bd9Sstevel@tonic-gate port, port_status);
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate /* Clear CSC bit */
5767c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port], port_status | HCR_PORT_CSC);
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate /* Update software port_changes register */
5797c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_changes[port] &= ~PORT_CHANGE_CSC;
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate /*
5847c478bd9Sstevel@tonic-gate * uhci_handle_get_port_status:
5857c478bd9Sstevel@tonic-gate * Handle a get port status request.
5867c478bd9Sstevel@tonic-gate */
5877c478bd9Sstevel@tonic-gate static void
uhci_handle_get_port_status(uhci_state_t * uhcip,usb_ctrl_req_t * req,usb_port_t port)5887c478bd9Sstevel@tonic-gate uhci_handle_get_port_status(
5897c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
5907c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req,
5917c478bd9Sstevel@tonic-gate usb_port_t port)
5927c478bd9Sstevel@tonic-gate {
5937c478bd9Sstevel@tonic-gate uint_t new_port_status;
5947c478bd9Sstevel@tonic-gate uint_t old_port_status =
595112116d8Sfb uhcip->uhci_root_hub.rh_port_status[port];
5967c478bd9Sstevel@tonic-gate uint_t old_port_changes =
597112116d8Sfb uhcip->uhci_root_hub.rh_port_changes[port];
5987c478bd9Sstevel@tonic-gate uint_t change_status;
5997c478bd9Sstevel@tonic-gate usb_ctrl_req_t *ctrl_reqp = (usb_ctrl_req_t *)req;
6007c478bd9Sstevel@tonic-gate uint16_t wLength = req->ctrl_wLength;
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate ASSERT(wLength == 4);
6037c478bd9Sstevel@tonic-gate ASSERT(ctrl_reqp->ctrl_data != NULL);
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate /* Read the current port status and return it */
6067c478bd9Sstevel@tonic-gate new_port_status = uhci_get_port_status(uhcip, port);
6077c478bd9Sstevel@tonic-gate change_status = (old_port_status ^ new_port_status) & 0xff;
6087c478bd9Sstevel@tonic-gate change_status |= old_port_changes;
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
6117c478bd9Sstevel@tonic-gate "uhci_handle_get_port_status:\n\t"
6127c478bd9Sstevel@tonic-gate "port%d: old status = 0x%x new status = 0x%x change = 0x%x",
6137c478bd9Sstevel@tonic-gate port, old_port_status, new_port_status, change_status);
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)new_port_status;
6167c478bd9Sstevel@tonic-gate *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)(new_port_status >> 8);
6177c478bd9Sstevel@tonic-gate *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)change_status;
6187c478bd9Sstevel@tonic-gate *ctrl_reqp->ctrl_data->b_wptr++ = (uchar_t)(change_status >> 8);
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate /* Update the status */
6217c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_status[port] = new_port_status;
6227c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_changes[port] = change_status;
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate /*
6277c478bd9Sstevel@tonic-gate * uhci_handle_get_hub_descriptor:
6287c478bd9Sstevel@tonic-gate */
6297c478bd9Sstevel@tonic-gate static void
uhci_handle_get_hub_descriptor(uhci_state_t * uhcip,usb_ctrl_req_t * req)6307c478bd9Sstevel@tonic-gate uhci_handle_get_hub_descriptor(
6317c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
6327c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate uchar_t raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
6357c478bd9Sstevel@tonic-gate usb_hub_descr_t *root_hub_descr = &uhcip->uhci_root_hub.rh_descr;
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
6387c478bd9Sstevel@tonic-gate "uhci_handle_get_hub_descriptor: wLength = 0x%x",
6397c478bd9Sstevel@tonic-gate req->ctrl_wLength);
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate ASSERT(req->ctrl_wLength != 0);
6427c478bd9Sstevel@tonic-gate ASSERT(req->ctrl_data != NULL);
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate raw_descr[0] = root_hub_descr->bDescLength;
6477c478bd9Sstevel@tonic-gate raw_descr[1] = root_hub_descr->bDescriptorType;
6487c478bd9Sstevel@tonic-gate raw_descr[2] = root_hub_descr->bNbrPorts;
6497c478bd9Sstevel@tonic-gate raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00ff;
6507c478bd9Sstevel@tonic-gate raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xff00) >> 8;
6517c478bd9Sstevel@tonic-gate raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
6527c478bd9Sstevel@tonic-gate raw_descr[6] = root_hub_descr->bHubContrCurrent;
6537c478bd9Sstevel@tonic-gate raw_descr[7] = root_hub_descr->DeviceRemovable;
6547c478bd9Sstevel@tonic-gate raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate bcopy(raw_descr, req->ctrl_data->b_wptr, req->ctrl_wLength);
6577c478bd9Sstevel@tonic-gate req->ctrl_data->b_wptr += req->ctrl_wLength;
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate /*
6627c478bd9Sstevel@tonic-gate * uhci_handle_get_hub_status:
6637c478bd9Sstevel@tonic-gate */
6647c478bd9Sstevel@tonic-gate static void
uhci_handle_get_hub_status(uhci_state_t * uhcip,usb_ctrl_req_t * req)6657c478bd9Sstevel@tonic-gate uhci_handle_get_hub_status(
6667c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
6677c478bd9Sstevel@tonic-gate usb_ctrl_req_t *req)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
6717c478bd9Sstevel@tonic-gate "uhci_handle_get_hub_status: wLength = 0x%x",
672112116d8Sfb req->ctrl_wLength);
6737c478bd9Sstevel@tonic-gate ASSERT(req->ctrl_wLength != 0);
6747c478bd9Sstevel@tonic-gate ASSERT(req->ctrl_data != NULL);
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate /*
6777c478bd9Sstevel@tonic-gate * A good status is always sent because there is no way that
6787c478bd9Sstevel@tonic-gate * the driver can get to know about the status change of the
6797c478bd9Sstevel@tonic-gate * over current or power failure of the root hub from the HC.
6807c478bd9Sstevel@tonic-gate */
6817c478bd9Sstevel@tonic-gate bzero(req->ctrl_data->b_wptr, req->ctrl_wLength);
6827c478bd9Sstevel@tonic-gate req->ctrl_data->b_wptr += req->ctrl_wLength;
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate
68635f36846Ssl /*
68735f36846Ssl * uhci_handle_get_device_status:
68835f36846Ssl */
68935f36846Ssl static void
uhci_handle_get_device_status(uhci_state_t * uhcip,usb_ctrl_req_t * req)69035f36846Ssl uhci_handle_get_device_status(
69135f36846Ssl uhci_state_t *uhcip,
69235f36846Ssl usb_ctrl_req_t *req)
69335f36846Ssl {
69435f36846Ssl uint16_t dev_status;
69535f36846Ssl
69635f36846Ssl USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
69735f36846Ssl "uhci_handle_get_device_status: wLength = 0x%x",
69835f36846Ssl req->ctrl_wLength);
69935f36846Ssl
70035f36846Ssl ASSERT(req->ctrl_wLength != 0);
70135f36846Ssl ASSERT(req->ctrl_data != NULL);
70235f36846Ssl
70335f36846Ssl /*
70435f36846Ssl * UHCI doesn't have device status information.
70535f36846Ssl * Simply return what is desired for the request.
70635f36846Ssl */
70735f36846Ssl dev_status = USB_DEV_SLF_PWRD_STATUS;
70835f36846Ssl
70935f36846Ssl *req->ctrl_data->b_wptr++ = (uchar_t)dev_status;
71035f36846Ssl *req->ctrl_data->b_wptr++ = (uchar_t)(dev_status >> 8);
71135f36846Ssl }
71235f36846Ssl
71335f36846Ssl
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate * uhci_handle_root_hub_status_change:
716*4f71203dSzl * This function is called every 256 ms from the time out handler.
7177c478bd9Sstevel@tonic-gate * It checks for the status change of the root hub and its ports.
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate void
uhci_handle_root_hub_status_change(void * arg)7207c478bd9Sstevel@tonic-gate uhci_handle_root_hub_status_change(void *arg)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate usb_port_t port;
7237c478bd9Sstevel@tonic-gate uint_t old_port_status;
7247c478bd9Sstevel@tonic-gate uint_t new_port_status;
7257c478bd9Sstevel@tonic-gate ushort_t port_status;
7267c478bd9Sstevel@tonic-gate uint_t change_status;
7277c478bd9Sstevel@tonic-gate uchar_t all_ports_status = 0;
7287c478bd9Sstevel@tonic-gate uhci_state_t *uhcip = (uhci_state_t *)arg;
7297c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate /* reset the timeout id */
7347c478bd9Sstevel@tonic-gate uhcip->uhci_timeout_id = 0;
7357c478bd9Sstevel@tonic-gate
7367c478bd9Sstevel@tonic-gate /* Get the current interrupt request pointer */
7377c478bd9Sstevel@tonic-gate curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate /* Check each port */
7407c478bd9Sstevel@tonic-gate for (port = 0; port < uhcip->uhci_root_hub.rh_num_ports; port++) {
7417c478bd9Sstevel@tonic-gate new_port_status = uhci_get_port_status(uhcip, port);
7427c478bd9Sstevel@tonic-gate old_port_status = uhcip->uhci_root_hub.rh_port_status[port];
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate change_status = (old_port_status ^ new_port_status) & 0xff;
7457c478bd9Sstevel@tonic-gate change_status |= uhcip->uhci_root_hub.rh_port_changes[port];
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate /* See if a device was attached/detached */
7487c478bd9Sstevel@tonic-gate if (change_status & PORT_STATUS_CCS) {
7497c478bd9Sstevel@tonic-gate all_ports_status |= 1 << (port + 1);
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate port_status = Get_OpReg16(PORTSC[port]);
7537c478bd9Sstevel@tonic-gate Set_OpReg16(PORTSC[port], port_status | HCR_PORT_ENDIS_CHG);
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_status[port] = new_port_status;
7567c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_port_changes[port] = change_status;
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
7597c478bd9Sstevel@tonic-gate "port %d old status 0x%x new status 0x%x change 0x%x\n\t"
7607c478bd9Sstevel@tonic-gate "all_ports_status = 0x%x", port, old_port_status,
7617c478bd9Sstevel@tonic-gate new_port_status, change_status, all_ports_status);
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate if (uhcip->uhci_root_hub.rh_intr_pipe_handle &&
7657c478bd9Sstevel@tonic-gate all_ports_status && curr_intr_reqp &&
7667c478bd9Sstevel@tonic-gate (uhcip->uhci_root_hub.rh_pipe_state == UHCI_PIPE_STATE_ACTIVE)) {
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate ASSERT(curr_intr_reqp->intr_data != NULL);
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate *curr_intr_reqp->intr_data->b_wptr++ = all_ports_status;
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate uhci_rh_hcdi_callback(uhcip,
7737c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_intr_pipe_handle,
7747c478bd9Sstevel@tonic-gate (usb_opaque_t)curr_intr_reqp, USB_CR_OK);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate if (uhcip->uhci_root_hub.rh_pipe_state == UHCI_PIPE_STATE_ACTIVE) {
7787c478bd9Sstevel@tonic-gate /*
7797c478bd9Sstevel@tonic-gate * If needed, allocate new interrupt request. Also
7807c478bd9Sstevel@tonic-gate * start the timer for the root hub interrupt polling.
7817c478bd9Sstevel@tonic-gate */
7827c478bd9Sstevel@tonic-gate if (uhci_root_hub_allocate_intr_pipe_resource(uhcip, 0) !=
7837c478bd9Sstevel@tonic-gate USB_SUCCESS) {
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate /* Do interrupt pipe cleanup */
7867c478bd9Sstevel@tonic-gate uhci_root_hub_intr_pipe_cleanup(uhcip,
787112116d8Sfb USB_CR_NO_RESOURCES);
7887c478bd9Sstevel@tonic-gate }
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate static uint_t
uhci_get_port_status(uhci_state_t * uhcip,usb_port_t port)7967c478bd9Sstevel@tonic-gate uhci_get_port_status(
7977c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
7987c478bd9Sstevel@tonic-gate usb_port_t port)
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate uint_t new_port_status = PORT_STATUS_PPS;
8017c478bd9Sstevel@tonic-gate ushort_t port_status = Get_OpReg16(PORTSC[port]);
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate if (port_status & HCR_PORT_CCS) {
8047c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_CCS;
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate if (port_status & HCR_PORT_LSDA) {
8087c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_LSDA;
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate if (port_status & HCR_PORT_ENABLE) {
8127c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_PES;
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate if (port_status & HCR_PORT_SUSPEND) {
8167c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_PSS;
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate if (port_status & HCR_PORT_RESET) {
8207c478bd9Sstevel@tonic-gate new_port_status |= PORT_STATUS_PRS;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate return (new_port_status);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * uhci_root_hub_allocate_intr_pipe_resource:
8297c478bd9Sstevel@tonic-gate * Allocate interrupt requests and initialize them.
8307c478bd9Sstevel@tonic-gate */
8317c478bd9Sstevel@tonic-gate int
uhci_root_hub_allocate_intr_pipe_resource(uhci_state_t * uhcip,usb_flags_t flags)8327c478bd9Sstevel@tonic-gate uhci_root_hub_allocate_intr_pipe_resource(
8337c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
8347c478bd9Sstevel@tonic-gate usb_flags_t flags)
8357c478bd9Sstevel@tonic-gate {
8367c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
8377c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
8407c478bd9Sstevel@tonic-gate "uhci_root_hub_allocate_intr_pipe_resource:");
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate /* Get the interrupt pipe handle */
8457c478bd9Sstevel@tonic-gate ph = uhcip->uhci_root_hub.rh_intr_pipe_handle;
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate /* Get the current interrupt request pointer */
8487c478bd9Sstevel@tonic-gate curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate * If current interrupt request pointer is null,
8527c478bd9Sstevel@tonic-gate * allocate new interrupt request.
8537c478bd9Sstevel@tonic-gate */
8547c478bd9Sstevel@tonic-gate if (curr_intr_reqp == NULL) {
8557c478bd9Sstevel@tonic-gate ASSERT(uhcip->uhci_root_hub.rh_client_intr_req);
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate if ((curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
8587c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req,
8597c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req->intr_len,
8607c478bd9Sstevel@tonic-gate flags)) == NULL) {
8617c478bd9Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
8627c478bd9Sstevel@tonic-gate "uhci_root_hub_allocate_intr_pipe_resource:"
8637c478bd9Sstevel@tonic-gate "Interrupt request structure allocation failed");
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate return (USB_NO_RESOURCES);
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate
8687c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
8717c478bd9Sstevel@tonic-gate ph->p_req_count++;
8727c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate if (uhcip->uhci_timeout_id == 0) {
8767c478bd9Sstevel@tonic-gate uhcip->uhci_timeout_id = timeout(
877112116d8Sfb uhci_handle_root_hub_status_change,
878*4f71203dSzl (void *)uhcip, UHCI_256_MS);
8797c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_pipe_state =
880112116d8Sfb UHCI_PIPE_STATE_ACTIVE;
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate return (USB_SUCCESS);
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate /*
8887c478bd9Sstevel@tonic-gate * uhci_root_hub_intr_pipe_cleanup:
8897c478bd9Sstevel@tonic-gate * Deallocate all interrupt requests and do callback
8907c478bd9Sstevel@tonic-gate * the original client interrupt request.
8917c478bd9Sstevel@tonic-gate */
8927c478bd9Sstevel@tonic-gate void
uhci_root_hub_intr_pipe_cleanup(uhci_state_t * uhcip,usb_cr_t cr)8937c478bd9Sstevel@tonic-gate uhci_root_hub_intr_pipe_cleanup(uhci_state_t *uhcip, usb_cr_t cr)
8947c478bd9Sstevel@tonic-gate {
8957c478bd9Sstevel@tonic-gate usb_intr_req_t *curr_intr_reqp;
8967c478bd9Sstevel@tonic-gate usb_opaque_t client_intr_reqp;
8977c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph;
8987c478bd9Sstevel@tonic-gate timeout_id_t timer_id;
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, uhcip->uhci_log_hdl,
9017c478bd9Sstevel@tonic-gate "uhci_root_hub_intr_pipe_cleanup:");
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate /* Get the interrupt pipe handle */
9067c478bd9Sstevel@tonic-gate ph = uhcip->uhci_root_hub.rh_intr_pipe_handle;
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate /* Get the interrupt timerid */
9097c478bd9Sstevel@tonic-gate timer_id = uhcip->uhci_timeout_id;
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /* Stop the root hub interrupt timer */
9127c478bd9Sstevel@tonic-gate if (timer_id) {
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate /* Reset the timer id to zero */
9157c478bd9Sstevel@tonic-gate uhcip->uhci_timeout_id = 0;
9167c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_pipe_state =
917112116d8Sfb UHCI_PIPE_STATE_IDLE;
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
9207c478bd9Sstevel@tonic-gate (void) untimeout(timer_id);
9217c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate /* Reset the current interrupt request pointer */
9257c478bd9Sstevel@tonic-gate curr_intr_reqp = uhcip->uhci_root_hub.rh_curr_intr_reqp;
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate /* Deallocate uncompleted interrupt request */
9287c478bd9Sstevel@tonic-gate if (curr_intr_reqp) {
9297c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL;
9307c478bd9Sstevel@tonic-gate usb_free_intr_req(curr_intr_reqp);
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate mutex_enter(&ph->p_mutex);
9337c478bd9Sstevel@tonic-gate ph->p_req_count--;
9347c478bd9Sstevel@tonic-gate mutex_exit(&ph->p_mutex);
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate
9377c478bd9Sstevel@tonic-gate client_intr_reqp = (usb_opaque_t)
9387c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req;
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate /* Callback for original client interrupt request */
9417c478bd9Sstevel@tonic-gate if (client_intr_reqp) {
9427c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req = NULL;
9437c478bd9Sstevel@tonic-gate uhci_rh_hcdi_callback(uhcip, ph,
9447c478bd9Sstevel@tonic-gate (usb_opaque_t)client_intr_reqp, cr);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate /*
9507c478bd9Sstevel@tonic-gate * uhci_rh_hcdi_callback:
9517c478bd9Sstevel@tonic-gate * Convenience wrapper around usba_hcdi_cb() for the root hub.
9527c478bd9Sstevel@tonic-gate */
9537c478bd9Sstevel@tonic-gate static void
uhci_rh_hcdi_callback(uhci_state_t * uhcip,usba_pipe_handle_data_t * ph,usb_opaque_t req,usb_cr_t cr)9547c478bd9Sstevel@tonic-gate uhci_rh_hcdi_callback(
9557c478bd9Sstevel@tonic-gate uhci_state_t *uhcip,
9567c478bd9Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
9577c478bd9Sstevel@tonic-gate usb_opaque_t req,
9587c478bd9Sstevel@tonic-gate usb_cr_t cr)
9597c478bd9Sstevel@tonic-gate {
9607c478bd9Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_HCDI, uhcip->uhci_log_hdl,
9617c478bd9Sstevel@tonic-gate "uhci_rh_hcdi_callback: ph=0x%p cr=0x%x req=0x%p",
962112116d8Sfb (void *)ph, cr, (void *)req);
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate switch (UHCI_XFER_TYPE(&ph->p_ep)) {
9677c478bd9Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate break;
9707c478bd9Sstevel@tonic-gate case USB_EP_ATTR_INTR:
9717c478bd9Sstevel@tonic-gate if ((usb_intr_req_t *)req ==
9727c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_curr_intr_reqp) {
9737c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_curr_intr_reqp = NULL;
9747c478bd9Sstevel@tonic-gate
9757c478bd9Sstevel@tonic-gate break;
9767c478bd9Sstevel@tonic-gate } else if ((usb_intr_req_t *)req ==
9777c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req) {
9787c478bd9Sstevel@tonic-gate uhcip->uhci_root_hub.rh_client_intr_req = NULL;
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate break;
9817c478bd9Sstevel@tonic-gate }
9827c478bd9Sstevel@tonic-gate /*FALLTHRU*/
9837c478bd9Sstevel@tonic-gate default:
9847c478bd9Sstevel@tonic-gate ASSERT(req);
9857c478bd9Sstevel@tonic-gate break;
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate mutex_exit(&uhcip->uhci_int_mutex);
9897c478bd9Sstevel@tonic-gate usba_hcdi_cb(ph, req, cr);
9907c478bd9Sstevel@tonic-gate mutex_enter(&uhcip->uhci_int_mutex);
9917c478bd9Sstevel@tonic-gate }
992