1e68fcc88STakanori Watanabe /* $FreeBSD$ */ 2e68fcc88STakanori Watanabe /*- 3e68fcc88STakanori Watanabe * SPDX-License-Identifier: BSD-2-Clause-NetBSD 4e68fcc88STakanori Watanabe * 5e68fcc88STakanori Watanabe * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 6e68fcc88STakanori Watanabe * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 7e68fcc88STakanori Watanabe * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. 8e68fcc88STakanori Watanabe * Copyright (c) 2019 Takanori Watanabe. 9e68fcc88STakanori Watanabe * 10e68fcc88STakanori Watanabe * Redistribution and use in source and binary forms, with or without 11e68fcc88STakanori Watanabe * modification, are permitted provided that the following conditions 12e68fcc88STakanori Watanabe * are met: 13e68fcc88STakanori Watanabe * 1. Redistributions of source code must retain the above copyright 14e68fcc88STakanori Watanabe * notice, this list of conditions and the following disclaimer. 15e68fcc88STakanori Watanabe * 2. Redistributions in binary form must reproduce the above copyright 16e68fcc88STakanori Watanabe * notice, this list of conditions and the following disclaimer in the 17e68fcc88STakanori Watanabe * documentation and/or other materials provided with the distribution. 18e68fcc88STakanori Watanabe * 19e68fcc88STakanori Watanabe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20e68fcc88STakanori Watanabe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21e68fcc88STakanori Watanabe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22e68fcc88STakanori Watanabe * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23e68fcc88STakanori Watanabe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24e68fcc88STakanori Watanabe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25e68fcc88STakanori Watanabe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26e68fcc88STakanori Watanabe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27e68fcc88STakanori Watanabe * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28e68fcc88STakanori Watanabe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29e68fcc88STakanori Watanabe * SUCH DAMAGE. 30e68fcc88STakanori Watanabe */ 31e68fcc88STakanori Watanabe 32e68fcc88STakanori Watanabe /* 33e68fcc88STakanori Watanabe * USB spec: http://www.usb.org/developers/docs/usbspec.zip 34e68fcc88STakanori Watanabe */ 35e68fcc88STakanori Watanabe 36e68fcc88STakanori Watanabe #ifdef USB_GLOBAL_INCLUDE_FILE 37e68fcc88STakanori Watanabe #include USB_GLOBAL_INCLUDE_FILE 38e68fcc88STakanori Watanabe #else 39e68fcc88STakanori Watanabe #include <sys/stdint.h> 40e68fcc88STakanori Watanabe #include <sys/stddef.h> 41e68fcc88STakanori Watanabe #include <sys/param.h> 42e68fcc88STakanori Watanabe #include <sys/queue.h> 43e68fcc88STakanori Watanabe #include <sys/types.h> 44e68fcc88STakanori Watanabe #include <sys/systm.h> 45e68fcc88STakanori Watanabe #include <sys/kernel.h> 46e68fcc88STakanori Watanabe #include <sys/bus.h> 47e68fcc88STakanori Watanabe #include <sys/module.h> 48e68fcc88STakanori Watanabe #include <sys/lock.h> 49e68fcc88STakanori Watanabe #include <sys/mutex.h> 50e68fcc88STakanori Watanabe #include <sys/condvar.h> 51e68fcc88STakanori Watanabe #include <sys/sysctl.h> 52e68fcc88STakanori Watanabe #include <sys/sx.h> 53e68fcc88STakanori Watanabe #include <sys/unistd.h> 54e68fcc88STakanori Watanabe #include <sys/callout.h> 55e68fcc88STakanori Watanabe #include <sys/malloc.h> 56e68fcc88STakanori Watanabe #include <sys/priv.h> 57e68fcc88STakanori Watanabe 58e68fcc88STakanori Watanabe #include <dev/usb/usb.h> 59e68fcc88STakanori Watanabe #include <dev/usb/usbdi.h> 60e68fcc88STakanori Watanabe #include <dev/usb/usbdi_util.h> 61e68fcc88STakanori Watanabe 62e68fcc88STakanori Watanabe #define USB_DEBUG_VAR uhub_debug 63e68fcc88STakanori Watanabe 64e68fcc88STakanori Watanabe #include <dev/usb/usb_core.h> 65e68fcc88STakanori Watanabe #include <dev/usb/usb_process.h> 66e68fcc88STakanori Watanabe #include <dev/usb/usb_device.h> 67e68fcc88STakanori Watanabe #include <dev/usb/usb_request.h> 68e68fcc88STakanori Watanabe #include <dev/usb/usb_debug.h> 69e68fcc88STakanori Watanabe #include <dev/usb/usb_hub.h> 70e68fcc88STakanori Watanabe #include <dev/usb/usb_util.h> 71e68fcc88STakanori Watanabe #include <dev/usb/usb_busdma.h> 72e68fcc88STakanori Watanabe #include <dev/usb/usb_transfer.h> 73e68fcc88STakanori Watanabe #include <dev/usb/usb_dynamic.h> 74e68fcc88STakanori Watanabe 75e68fcc88STakanori Watanabe #include <dev/usb/usb_controller.h> 76e68fcc88STakanori Watanabe #include <dev/usb/usb_bus.h> 77e68fcc88STakanori Watanabe #endif /* USB_GLOBAL_INCLUDE_FILE */ 78e68fcc88STakanori Watanabe #include <dev/usb/usb_hub_private.h> 79e68fcc88STakanori Watanabe #include <contrib/dev/acpica/include/acpi.h> 80e68fcc88STakanori Watanabe #include <contrib/dev/acpica/include/accommon.h> 81e68fcc88STakanori Watanabe #include <dev/acpica/acpivar.h> 825f0099fcSTakanori Watanabe #include <sys/sbuf.h> 835f0099fcSTakanori Watanabe 845f0099fcSTakanori Watanabe #define ACPI_PLD_SIZE 20 855f0099fcSTakanori Watanabe struct acpi_uhub_port { 865f0099fcSTakanori Watanabe ACPI_HANDLE handle; 875f0099fcSTakanori Watanabe #define ACPI_UPC_CONNECTABLE 0x80000000 885f0099fcSTakanori Watanabe #define ACPI_UPC_PORTTYPE(x) ((x)&0xff) 895f0099fcSTakanori Watanabe uint32_t upc; 905f0099fcSTakanori Watanabe uint8_t pld[ACPI_PLD_SIZE]; 915f0099fcSTakanori Watanabe }; 92e68fcc88STakanori Watanabe 93e68fcc88STakanori Watanabe struct acpi_uhub_softc { 94e68fcc88STakanori Watanabe struct uhub_softc usc; 95e68fcc88STakanori Watanabe uint8_t nports; 965f0099fcSTakanori Watanabe ACPI_HANDLE ah; 975f0099fcSTakanori Watanabe struct acpi_uhub_port *port; 98e68fcc88STakanori Watanabe }; 99e68fcc88STakanori Watanabe 10074d565fdSHans Petter Selasky static UINT32 10174d565fdSHans Petter Selasky acpi_uhub_find_rh_cb(ACPI_HANDLE ah, UINT32 nl, void *ctx, void **status) 10274d565fdSHans Petter Selasky { 103e68fcc88STakanori Watanabe ACPI_DEVICE_INFO *devinfo; 10474d565fdSHans Petter Selasky UINT32 ret; 105e68fcc88STakanori Watanabe 106e68fcc88STakanori Watanabe *status = NULL; 107e68fcc88STakanori Watanabe devinfo = NULL; 108e68fcc88STakanori Watanabe 109e68fcc88STakanori Watanabe ret = AcpiGetObjectInfo(ah, &devinfo); 11074d565fdSHans Petter Selasky if (ACPI_SUCCESS(ret)) { 111e68fcc88STakanori Watanabe if ((devinfo->Valid & ACPI_VALID_ADR) && 112e68fcc88STakanori Watanabe (devinfo->Address == 0)) { 113e68fcc88STakanori Watanabe ret = AE_CTRL_TERMINATE; 114e68fcc88STakanori Watanabe *status = ah; 115e68fcc88STakanori Watanabe } 116e68fcc88STakanori Watanabe AcpiOsFree(devinfo); 11774d565fdSHans Petter Selasky } 11874d565fdSHans Petter Selasky return (ret); 119e68fcc88STakanori Watanabe } 120e68fcc88STakanori Watanabe 1215f0099fcSTakanori Watanabe static const char * 1225f0099fcSTakanori Watanabe acpi_uhub_upc_type(uint8_t type) 1235f0099fcSTakanori Watanabe { 1245f0099fcSTakanori Watanabe const char *typelist[] = {"TypeA", "MiniAB", "Express", 1255f0099fcSTakanori Watanabe "USB3-A", "USB3-B", "USB-MicroB", 1265f0099fcSTakanori Watanabe "USB3-MicroAB", "USB3-PowerB", 1275f0099fcSTakanori Watanabe "TypeC-USB2", "TypeC-Switch", 1285f0099fcSTakanori Watanabe "TypeC-nonSwitch"}; 1295f0099fcSTakanori Watanabe const int last = sizeof(typelist) / sizeof(typelist[0]); 1305f0099fcSTakanori Watanabe 1315f0099fcSTakanori Watanabe if (type == 0xff) { 1325f0099fcSTakanori Watanabe return "Proprietary"; 1335f0099fcSTakanori Watanabe } 1345f0099fcSTakanori Watanabe 1355f0099fcSTakanori Watanabe return (type < last) ? typelist[type] : "Unknown"; 1365f0099fcSTakanori Watanabe } 1375f0099fcSTakanori Watanabe 138e68fcc88STakanori Watanabe static int 139*62d42655SHans Petter Selasky acpi_uhub_parse_upc(device_t dev, unsigned p, ACPI_HANDLE ah, struct sysctl_oid_list *poid) 140e68fcc88STakanori Watanabe { 141e68fcc88STakanori Watanabe ACPI_BUFFER buf; 1425f0099fcSTakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 1435f0099fcSTakanori Watanabe struct acpi_uhub_port *port = &sc->port[p - 1]; 144e68fcc88STakanori Watanabe 145e68fcc88STakanori Watanabe buf.Pointer = NULL; 146e68fcc88STakanori Watanabe buf.Length = ACPI_ALLOCATE_BUFFER; 14774d565fdSHans Petter Selasky 148e68fcc88STakanori Watanabe if (AcpiEvaluateObject(ah, "_UPC", NULL, &buf) == AE_OK) { 149e68fcc88STakanori Watanabe ACPI_OBJECT *obj = buf.Pointer; 1505f0099fcSTakanori Watanabe UINT64 porttypenum, conn; 1515f0099fcSTakanori Watanabe uint8_t *connectable; 152e68fcc88STakanori Watanabe 153e68fcc88STakanori Watanabe acpi_PkgInt(obj, 0, &conn); 154e68fcc88STakanori Watanabe acpi_PkgInt(obj, 1, &porttypenum); 155e68fcc88STakanori Watanabe connectable = conn ? "" : "non"; 1565f0099fcSTakanori Watanabe 1575f0099fcSTakanori Watanabe port->upc = porttypenum; 1585f0099fcSTakanori Watanabe port->upc |= (conn) ? (ACPI_UPC_CONNECTABLE) : 0; 1595f0099fcSTakanori Watanabe 160e68fcc88STakanori Watanabe if (usb_debug) 161e68fcc88STakanori Watanabe device_printf(dev, "Port %u %sconnectable %s\n", 1625f0099fcSTakanori Watanabe p, connectable, 1635f0099fcSTakanori Watanabe acpi_uhub_upc_type(porttypenum)); 1645f0099fcSTakanori Watanabe 1655f0099fcSTakanori Watanabe SYSCTL_ADD_U32( 1665f0099fcSTakanori Watanabe device_get_sysctl_ctx(dev), 1675f0099fcSTakanori Watanabe poid, OID_AUTO, 1685f0099fcSTakanori Watanabe "upc", 1695f0099fcSTakanori Watanabe CTLFLAG_RD | CTLFLAG_MPSAFE, 1705f0099fcSTakanori Watanabe SYSCTL_NULL_U32_PTR, port->upc, 1715f0099fcSTakanori Watanabe "UPC value. MSB is visible flag"); 172e68fcc88STakanori Watanabe } 173e68fcc88STakanori Watanabe AcpiOsFree(buf.Pointer); 174e68fcc88STakanori Watanabe 17574d565fdSHans Petter Selasky return (0); 176e68fcc88STakanori Watanabe } 1775f0099fcSTakanori Watanabe static int 1785f0099fcSTakanori Watanabe acpi_uhub_port_sysctl(SYSCTL_HANDLER_ARGS) 1795f0099fcSTakanori Watanabe { 1805f0099fcSTakanori Watanabe struct acpi_uhub_port *port = oidp->oid_arg1; 1815f0099fcSTakanori Watanabe struct sbuf sb; 1825f0099fcSTakanori Watanabe int error; 1835f0099fcSTakanori Watanabe 1845f0099fcSTakanori Watanabe sbuf_new_for_sysctl(&sb, NULL, 256, req); 1855f0099fcSTakanori Watanabe sbuf_printf(&sb, "Handle %s\n", acpi_name(port->handle)); 1865f0099fcSTakanori Watanabe if (port->upc == 0xffffffff) { 1875f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tNo information\n"); 1885f0099fcSTakanori Watanabe goto end; 1895f0099fcSTakanori Watanabe } 1905f0099fcSTakanori Watanabe sbuf_printf(&sb, "\t"); 1915f0099fcSTakanori Watanabe if (port->upc & ACPI_UPC_CONNECTABLE) { 1925f0099fcSTakanori Watanabe sbuf_printf(&sb, "Connectable "); 1935f0099fcSTakanori Watanabe } 1945f0099fcSTakanori Watanabe sbuf_printf(&sb, "%s port\n", acpi_uhub_upc_type(port->upc & 0xff)); 1955f0099fcSTakanori Watanabe 1965f0099fcSTakanori Watanabe if ((port->pld[0] & 0x80) == 0) { 1975f0099fcSTakanori Watanabe sbuf_printf(&sb, 1985f0099fcSTakanori Watanabe "\tColor:#%02x%02x%02x\n", 1995f0099fcSTakanori Watanabe port->pld[1], port->pld[2], 2005f0099fcSTakanori Watanabe port->pld[3]); 2015f0099fcSTakanori Watanabe } 2025f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tWidth %d mm Height %d mm\n", 2035f0099fcSTakanori Watanabe port->pld[4] | (port->pld[5] << 8), 2045f0099fcSTakanori Watanabe port->pld[6] | (port->pld[7] << 8)); 2055f0099fcSTakanori Watanabe if (port->pld[8] & 1) { 2065f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tVisible\n"); 2075f0099fcSTakanori Watanabe } 2085f0099fcSTakanori Watanabe if (port->pld[8] & 2) { 2095f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tDock\n"); 2105f0099fcSTakanori Watanabe } 2115f0099fcSTakanori Watanabe if (port->pld[8] & 4) { 2125f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tLid\n"); 2135f0099fcSTakanori Watanabe } { 2145f0099fcSTakanori Watanabe int panelpos = (port->pld[8] >> 3) & 7; 2155f0099fcSTakanori Watanabe const char *panposstr[] = {"Top", "Bottom", "Left", 2165f0099fcSTakanori Watanabe "Right", "Front", "Back", 2175f0099fcSTakanori Watanabe "Unknown", "Invalid"}; 2185f0099fcSTakanori Watanabe const char *shapestr[] = { 2195f0099fcSTakanori Watanabe "Round", "Oval", "Square", "VRect", "HRect", 2205f0099fcSTakanori Watanabe "VTrape", "HTrape", "Unknown", "Chamferd", 2215f0099fcSTakanori Watanabe "Rsvd", "Rsvd", "Rsvd", "Rsvd", 2225f0099fcSTakanori Watanabe "Rsvd", "Rsvd", "Rsvd", "Rsvd"}; 2235f0099fcSTakanori Watanabe 2245f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tPanelPosition: %s\n", panposstr[panelpos]); 2255f0099fcSTakanori Watanabe if (panelpos < 6) { 2265f0099fcSTakanori Watanabe const char *posstr[] = {"Upper", "Center", 2275f0099fcSTakanori Watanabe "Lower", "Invalid"}; 2285f0099fcSTakanori Watanabe 2295f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tVertPosition: %s\n", 2305f0099fcSTakanori Watanabe posstr[(port->pld[8] >> 6) & 3]); 2315f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tHorizPosition: %s\n", 2325f0099fcSTakanori Watanabe posstr[(port->pld[9]) & 3]); 2335f0099fcSTakanori Watanabe } 2345f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tShape: %s\n", 2355f0099fcSTakanori Watanabe shapestr[(port->pld[9] >> 2) & 0xf]); 2365f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tGroup Orientation %s\n", 2375f0099fcSTakanori Watanabe ((port->pld[9] >> 6) & 1) ? "Vertical" : 2385f0099fcSTakanori Watanabe "Horizontal"); 2395f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tGroupToken %x\n", 2405f0099fcSTakanori Watanabe ((port->pld[9] >> 7) 2415f0099fcSTakanori Watanabe | (port->pld[10] << 1)) & 0xff); 2425f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tGroupPosition %x\n", 2435f0099fcSTakanori Watanabe ((port->pld[10] >> 7) 2445f0099fcSTakanori Watanabe | (port->pld[11] << 1)) & 0xff); 2455f0099fcSTakanori Watanabe sbuf_printf(&sb, "\t%s %s %s\n", 2465f0099fcSTakanori Watanabe (port->pld[11] & 0x80) ? 2475f0099fcSTakanori Watanabe "Bay" : "", 2485f0099fcSTakanori Watanabe (port->pld[12] & 1) ? "Eject" : "", 2495f0099fcSTakanori Watanabe (port->pld[12] & 2) ? "OSPM" : "" 2505f0099fcSTakanori Watanabe ); 2515f0099fcSTakanori Watanabe } 2525f0099fcSTakanori Watanabe if ((port->pld[0] & 0x7f) >= 2) { 2535f0099fcSTakanori Watanabe sbuf_printf(&sb, "\tVOFF%d mm HOFF %dmm", 2545f0099fcSTakanori Watanabe port->pld[16] | (port->pld[17] << 8), 2555f0099fcSTakanori Watanabe port->pld[18] | (port->pld[19] << 8)); 2565f0099fcSTakanori Watanabe } 2575f0099fcSTakanori Watanabe 2585f0099fcSTakanori Watanabe end: 2595f0099fcSTakanori Watanabe error = sbuf_finish(&sb); 2605f0099fcSTakanori Watanabe sbuf_delete(&sb); 2615f0099fcSTakanori Watanabe return (error); 2625f0099fcSTakanori Watanabe } 263e68fcc88STakanori Watanabe 264e68fcc88STakanori Watanabe static int 265*62d42655SHans Petter Selasky acpi_uhub_parse_pld(device_t dev, unsigned p, ACPI_HANDLE ah, struct sysctl_oid_list *tree) 266e68fcc88STakanori Watanabe { 267e68fcc88STakanori Watanabe ACPI_BUFFER buf; 2685f0099fcSTakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 2695f0099fcSTakanori Watanabe struct acpi_uhub_port *port = &sc->port[p - 1]; 270e68fcc88STakanori Watanabe 271e68fcc88STakanori Watanabe buf.Pointer = NULL; 272e68fcc88STakanori Watanabe buf.Length = ACPI_ALLOCATE_BUFFER; 27374d565fdSHans Petter Selasky 274e68fcc88STakanori Watanabe if (AcpiEvaluateObject(ah, "_PLD", NULL, &buf) == AE_OK) { 275e68fcc88STakanori Watanabe ACPI_OBJECT *obj; 276e68fcc88STakanori Watanabe unsigned char *resbuf; 277e68fcc88STakanori Watanabe int len; 278e68fcc88STakanori Watanabe 279e68fcc88STakanori Watanabe obj = buf.Pointer; 280e68fcc88STakanori Watanabe 281e68fcc88STakanori Watanabe if (obj->Type == ACPI_TYPE_PACKAGE 282e68fcc88STakanori Watanabe && obj->Package.Elements[0].Type == ACPI_TYPE_BUFFER) { 283e68fcc88STakanori Watanabe ACPI_OBJECT *obj1; 284e68fcc88STakanori Watanabe 285e68fcc88STakanori Watanabe obj1 = &obj->Package.Elements[0]; 286e68fcc88STakanori Watanabe len = obj1->Buffer.Length; 287e68fcc88STakanori Watanabe resbuf = obj1->Buffer.Pointer; 288e68fcc88STakanori Watanabe } else if (obj->Type == ACPI_TYPE_BUFFER) { 289e68fcc88STakanori Watanabe len = obj->Buffer.Length; 290e68fcc88STakanori Watanabe resbuf = obj->Buffer.Pointer; 291e68fcc88STakanori Watanabe } else { 292e68fcc88STakanori Watanabe goto skip; 293e68fcc88STakanori Watanabe } 2945f0099fcSTakanori Watanabe len = (len < ACPI_PLD_SIZE) ? len : ACPI_PLD_SIZE; 2955f0099fcSTakanori Watanabe memcpy(port->pld, resbuf, len); 2965f0099fcSTakanori Watanabe SYSCTL_ADD_OPAQUE( 2975f0099fcSTakanori Watanabe device_get_sysctl_ctx(dev), tree, OID_AUTO, 2985f0099fcSTakanori Watanabe "pldraw", CTLFLAG_RD | CTLFLAG_MPSAFE, 2995f0099fcSTakanori Watanabe port->pld, len, "A", "Raw PLD value"); 3005f0099fcSTakanori Watanabe 301e68fcc88STakanori Watanabe if (usb_debug) { 302e68fcc88STakanori Watanabe device_printf(dev, "Revision:%d\n", 303e68fcc88STakanori Watanabe resbuf[0] & 0x7f); 304e68fcc88STakanori Watanabe if ((resbuf[0] & 0x80) == 0) { 305e68fcc88STakanori Watanabe device_printf(dev, 306e68fcc88STakanori Watanabe "Color:#%02x%02x%02x\n", 307e68fcc88STakanori Watanabe resbuf[1], resbuf[2], 308e68fcc88STakanori Watanabe resbuf[3]); 309e68fcc88STakanori Watanabe } 310e68fcc88STakanori Watanabe device_printf(dev, "Width %d mm Height %d mm\n", 311e68fcc88STakanori Watanabe resbuf[4] | (resbuf[5] << 8), 312e68fcc88STakanori Watanabe resbuf[6] | (resbuf[7] << 8)); 313e68fcc88STakanori Watanabe if (resbuf[8] & 1) { 314e68fcc88STakanori Watanabe device_printf(dev, "Visible\n"); 315e68fcc88STakanori Watanabe } 316e68fcc88STakanori Watanabe if (resbuf[8] & 2) { 317e68fcc88STakanori Watanabe device_printf(dev, "Dock\n"); 318e68fcc88STakanori Watanabe } 319e68fcc88STakanori Watanabe if (resbuf[8] & 4) { 320e68fcc88STakanori Watanabe device_printf(dev, "Lid\n"); 321e68fcc88STakanori Watanabe } 322e68fcc88STakanori Watanabe device_printf(dev, "PanelPosition: %d\n", 323e68fcc88STakanori Watanabe (resbuf[8] >> 3) & 7); 324e68fcc88STakanori Watanabe device_printf(dev, "VertPosition: %d\n", 325e68fcc88STakanori Watanabe (resbuf[8] >> 6) & 3); 326e68fcc88STakanori Watanabe device_printf(dev, "HorizPosition: %d\n", 327e68fcc88STakanori Watanabe (resbuf[9]) & 3); 328e68fcc88STakanori Watanabe device_printf(dev, "Shape: %d\n", 329e68fcc88STakanori Watanabe (resbuf[9] >> 2) & 0xf); 330e68fcc88STakanori Watanabe device_printf(dev, "80: %02x, %02x, %02x\n", 331e68fcc88STakanori Watanabe resbuf[9], resbuf[10], resbuf[11]); 332e68fcc88STakanori Watanabe device_printf(dev, "96: %02x, %02x, %02x, %02x\n", 333e68fcc88STakanori Watanabe resbuf[12], resbuf[13], 334e68fcc88STakanori Watanabe resbuf[14], resbuf[15]); 335e68fcc88STakanori Watanabe 336e68fcc88STakanori Watanabe if ((resbuf[0] & 0x7f) >= 2) { 337e68fcc88STakanori Watanabe device_printf(dev, "VOFF%d mm HOFF %dmm", 338e68fcc88STakanori Watanabe resbuf[16] | (resbuf[17] << 8), 339e68fcc88STakanori Watanabe resbuf[18] | (resbuf[19] << 8)); 340e68fcc88STakanori Watanabe } 341e68fcc88STakanori Watanabe } 342e68fcc88STakanori Watanabe skip: 343e68fcc88STakanori Watanabe AcpiOsFree(buf.Pointer); 34474d565fdSHans Petter Selasky } 34574d565fdSHans Petter Selasky return (0); 346e68fcc88STakanori Watanabe } 347e68fcc88STakanori Watanabe 34874d565fdSHans Petter Selasky static ACPI_STATUS 349a809abd4STakanori Watanabe acpi_uhub_find_rh(device_t dev, ACPI_HANDLE *ah) 350a809abd4STakanori Watanabe { 351e68fcc88STakanori Watanabe device_t grand; 352e68fcc88STakanori Watanabe ACPI_HANDLE gah; 353e68fcc88STakanori Watanabe 354a809abd4STakanori Watanabe *ah = NULL; 355e68fcc88STakanori Watanabe grand = device_get_parent(device_get_parent(dev)); 35674d565fdSHans Petter Selasky 35774d565fdSHans Petter Selasky if ((gah = acpi_get_handle(grand)) == NULL) 35874d565fdSHans Petter Selasky return (AE_ERROR); 35974d565fdSHans Petter Selasky 36074d565fdSHans Petter Selasky return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1, 36174d565fdSHans Petter Selasky acpi_uhub_find_rh_cb, NULL, dev, ah)); 362e68fcc88STakanori Watanabe } 363e68fcc88STakanori Watanabe 36474d565fdSHans Petter Selasky static ACPI_STATUS 365a809abd4STakanori Watanabe acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv) 366a809abd4STakanori Watanabe { 367e68fcc88STakanori Watanabe ACPI_DEVICE_INFO *devinfo; 368e68fcc88STakanori Watanabe device_t dev = ctx; 369e68fcc88STakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 37074d565fdSHans Petter Selasky UINT32 ret; 371e68fcc88STakanori Watanabe 37274d565fdSHans Petter Selasky ret = AcpiGetObjectInfo(ah, &devinfo); 37374d565fdSHans Petter Selasky if (ACPI_SUCCESS(ret)) { 374e68fcc88STakanori Watanabe if ((devinfo->Valid & ACPI_VALID_ADR) && 375e68fcc88STakanori Watanabe (devinfo->Address > 0) && 376e68fcc88STakanori Watanabe (devinfo->Address <= (uint64_t)sc->nports)) { 3775f0099fcSTakanori Watanabe char buf[] = "portXXX"; 3785f0099fcSTakanori Watanabe struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 3795f0099fcSTakanori Watanabe struct sysctl_oid *oid; 3805f0099fcSTakanori Watanabe struct sysctl_oid_list *tree; 3815f0099fcSTakanori Watanabe 38283b50693SKonstantin Belousov snprintf(buf, sizeof(buf), "port%ju", 38383b50693SKonstantin Belousov (uintmax_t)devinfo->Address); 3845f0099fcSTakanori Watanabe oid = SYSCTL_ADD_NODE(ctx, 385f8d2b1f3SPawel Biernacki SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 386f8d2b1f3SPawel Biernacki OID_AUTO, buf, CTLFLAG_RD | CTLFLAG_MPSAFE, 3875f0099fcSTakanori Watanabe NULL, "port nodes"); 3885f0099fcSTakanori Watanabe tree = SYSCTL_CHILDREN(oid); 3895f0099fcSTakanori Watanabe sc->port[devinfo->Address - 1].handle = ah; 3905f0099fcSTakanori Watanabe sc->port[devinfo->Address - 1].upc = 0xffffffff; 3915f0099fcSTakanori Watanabe acpi_uhub_parse_upc(dev, devinfo->Address, ah, tree); 3925f0099fcSTakanori Watanabe acpi_uhub_parse_pld(dev, devinfo->Address, ah, tree); 393f8d2b1f3SPawel Biernacki SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), tree, 394f8d2b1f3SPawel Biernacki OID_AUTO, "info", 395f8d2b1f3SPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 3965f0099fcSTakanori Watanabe &sc->port[devinfo->Address - 1], 0, 397f8d2b1f3SPawel Biernacki acpi_uhub_port_sysctl, "A", "Port information"); 398e68fcc88STakanori Watanabe } 399e68fcc88STakanori Watanabe AcpiOsFree(devinfo); 40074d565fdSHans Petter Selasky } 40174d565fdSHans Petter Selasky return (AE_OK); 402e68fcc88STakanori Watanabe } 403e68fcc88STakanori Watanabe 40474d565fdSHans Petter Selasky static ACPI_STATUS 405a809abd4STakanori Watanabe acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah) 406a809abd4STakanori Watanabe { 40774d565fdSHans Petter Selasky return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, 408e68fcc88STakanori Watanabe ah, 1, 409e68fcc88STakanori Watanabe acpi_usb_hub_port_probe_cb, 41074d565fdSHans Petter Selasky NULL, dev, NULL)); 411e68fcc88STakanori Watanabe } 41274d565fdSHans Petter Selasky 41374d565fdSHans Petter Selasky static int 414e68fcc88STakanori Watanabe acpi_uhub_root_probe(device_t dev) 415e68fcc88STakanori Watanabe { 416e68fcc88STakanori Watanabe ACPI_STATUS status; 41774d565fdSHans Petter Selasky ACPI_HANDLE ah; 418e68fcc88STakanori Watanabe 41974d565fdSHans Petter Selasky if (acpi_disabled("usb")) 42074d565fdSHans Petter Selasky return (ENXIO); 42174d565fdSHans Petter Selasky 422e68fcc88STakanori Watanabe status = acpi_uhub_find_rh(dev, &ah); 42374d565fdSHans Petter Selasky if (ACPI_SUCCESS(status) && ah != NULL && 42474d565fdSHans Petter Selasky uhub_probe(dev) <= 0) { 42574d565fdSHans Petter Selasky /* success prior than non-ACPI USB HUB */ 426e68fcc88STakanori Watanabe return (BUS_PROBE_DEFAULT + 1); 427e68fcc88STakanori Watanabe } 428e68fcc88STakanori Watanabe return (ENXIO); 429e68fcc88STakanori Watanabe } 43074d565fdSHans Petter Selasky 43174d565fdSHans Petter Selasky static int 43274d565fdSHans Petter Selasky acpi_uhub_probe(device_t dev) 43374d565fdSHans Petter Selasky { 43474d565fdSHans Petter Selasky ACPI_HANDLE ah; 43574d565fdSHans Petter Selasky 43674d565fdSHans Petter Selasky if (acpi_disabled("usb")) 43774d565fdSHans Petter Selasky return (ENXIO); 43874d565fdSHans Petter Selasky 43974d565fdSHans Petter Selasky ah = acpi_get_handle(dev); 44074d565fdSHans Petter Selasky if (ah == NULL) 44174d565fdSHans Petter Selasky return (ENXIO); 44274d565fdSHans Petter Selasky 44374d565fdSHans Petter Selasky if (uhub_probe(dev) <= 0) { 44474d565fdSHans Petter Selasky /* success prior than non-ACPI USB HUB */ 44574d565fdSHans Petter Selasky return (BUS_PROBE_DEFAULT + 1); 44674d565fdSHans Petter Selasky } 44774d565fdSHans Petter Selasky return (ENXIO); 44874d565fdSHans Petter Selasky } 4495f0099fcSTakanori Watanabe static int 4505f0099fcSTakanori Watanabe acpi_uhub_attach_common(device_t dev) 4515f0099fcSTakanori Watanabe { 4525f0099fcSTakanori Watanabe struct usb_hub *uh; 4535f0099fcSTakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 4545f0099fcSTakanori Watanabe ACPI_STATUS status; 4555f0099fcSTakanori Watanabe int ret = ENXIO; 4565f0099fcSTakanori Watanabe 4575f0099fcSTakanori Watanabe uh = sc->usc.sc_udev->hub; 4585f0099fcSTakanori Watanabe sc->nports = uh->nports; 4595f0099fcSTakanori Watanabe sc->port = malloc(sizeof(struct acpi_uhub_port) * uh->nports, 4605f0099fcSTakanori Watanabe M_USBDEV, M_WAITOK | M_ZERO); 4615f0099fcSTakanori Watanabe status = acpi_usb_hub_port_probe(dev, sc->ah); 4625f0099fcSTakanori Watanabe 4635f0099fcSTakanori Watanabe if (ACPI_SUCCESS(status)){ 4645f0099fcSTakanori Watanabe ret = 0; 4655f0099fcSTakanori Watanabe } 4665f0099fcSTakanori Watanabe 4675f0099fcSTakanori Watanabe return (ret); 4685f0099fcSTakanori Watanabe } 4695f0099fcSTakanori Watanabe 4705f0099fcSTakanori Watanabe static int 4715f0099fcSTakanori Watanabe acpi_uhub_detach(device_t dev) 4725f0099fcSTakanori Watanabe { 4735f0099fcSTakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 4745f0099fcSTakanori Watanabe 4755f0099fcSTakanori Watanabe free(sc->port, M_USBDEV); 4765f0099fcSTakanori Watanabe 4775f0099fcSTakanori Watanabe return (uhub_detach(dev)); 4785f0099fcSTakanori Watanabe } 47974d565fdSHans Petter Selasky 48074d565fdSHans Petter Selasky static int 481e68fcc88STakanori Watanabe acpi_uhub_root_attach(device_t dev) 482e68fcc88STakanori Watanabe { 483e68fcc88STakanori Watanabe int ret; 4845f0099fcSTakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 485e68fcc88STakanori Watanabe 4865f0099fcSTakanori Watanabe if (ACPI_FAILURE(acpi_uhub_find_rh(dev, &sc->ah)) || 4875f0099fcSTakanori Watanabe (sc->ah == NULL)) { 4885f0099fcSTakanori Watanabe return (ENXIO); 48974d565fdSHans Petter Selasky } 4905f0099fcSTakanori Watanabe if ((ret = uhub_attach(dev)) != 0) { 49174d565fdSHans Petter Selasky return (ret); 492e68fcc88STakanori Watanabe } 493e68fcc88STakanori Watanabe 4945f0099fcSTakanori Watanabe if ((ret = acpi_uhub_attach_common(dev)) != 0) { 4955f0099fcSTakanori Watanabe acpi_uhub_detach(dev); 4965f0099fcSTakanori Watanabe } 4975f0099fcSTakanori Watanabe return ret; 4985f0099fcSTakanori Watanabe } 4995f0099fcSTakanori Watanabe 50074d565fdSHans Petter Selasky static int 501e68fcc88STakanori Watanabe acpi_uhub_attach(device_t dev) 502e68fcc88STakanori Watanabe { 503e68fcc88STakanori Watanabe int ret; 5045f0099fcSTakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 505e68fcc88STakanori Watanabe 5065f0099fcSTakanori Watanabe sc->ah = acpi_get_handle(dev); 507e68fcc88STakanori Watanabe 5085f0099fcSTakanori Watanabe if (sc->ah == NULL) { 5095f0099fcSTakanori Watanabe return (ENXIO); 51074d565fdSHans Petter Selasky } 5115f0099fcSTakanori Watanabe if ((ret = uhub_attach(dev)) != 0) { 5125f0099fcSTakanori Watanabe return (ret); 5135f0099fcSTakanori Watanabe } 5145f0099fcSTakanori Watanabe 5155f0099fcSTakanori Watanabe if ((ret = acpi_uhub_attach_common(dev)) != 0) { 5165f0099fcSTakanori Watanabe acpi_uhub_detach(dev); 5175f0099fcSTakanori Watanabe } 5185f0099fcSTakanori Watanabe 51974d565fdSHans Petter Selasky return (ret); 520e68fcc88STakanori Watanabe } 521e68fcc88STakanori Watanabe 52274d565fdSHans Petter Selasky static int 52374d565fdSHans Petter Selasky acpi_uhub_read_ivar(device_t dev, device_t child, int idx, uintptr_t *res) 524e68fcc88STakanori Watanabe { 525e68fcc88STakanori Watanabe struct hub_result hres; 526e68fcc88STakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 527e68fcc88STakanori Watanabe ACPI_HANDLE ah; 528e68fcc88STakanori Watanabe 5295e203517SHans Petter Selasky bus_topo_lock(); 530e68fcc88STakanori Watanabe uhub_find_iface_index(sc->usc.sc_udev->hub, child, &hres); 5315e203517SHans Petter Selasky bus_topo_unlock(); 53274d565fdSHans Petter Selasky 533e68fcc88STakanori Watanabe if ((idx == ACPI_IVAR_HANDLE) && 534e68fcc88STakanori Watanabe (hres.portno > 0) && 535e68fcc88STakanori Watanabe (hres.portno <= sc->nports) && 5365f0099fcSTakanori Watanabe (ah = sc->port[hres.portno - 1].handle)) { 537e68fcc88STakanori Watanabe *res = (uintptr_t)ah; 538e68fcc88STakanori Watanabe return (0); 539e68fcc88STakanori Watanabe } 540e68fcc88STakanori Watanabe return (ENXIO); 541e68fcc88STakanori Watanabe } 54274d565fdSHans Petter Selasky 543e68fcc88STakanori Watanabe static int 544ddfc9c4cSWarner Losh acpi_uhub_child_location(device_t parent, device_t child, struct sbuf *sb) 545e68fcc88STakanori Watanabe { 546e68fcc88STakanori Watanabe ACPI_HANDLE ah; 547e68fcc88STakanori Watanabe 548ddfc9c4cSWarner Losh uhub_child_location(parent, child, sb); 54974d565fdSHans Petter Selasky 550e68fcc88STakanori Watanabe ah = acpi_get_handle(child); 551ddfc9c4cSWarner Losh if (ah != NULL) 552ddfc9c4cSWarner Losh sbuf_printf(sb, " handle=%s", acpi_name(ah)); 553e68fcc88STakanori Watanabe return (0); 554e68fcc88STakanori Watanabe } 555e68fcc88STakanori Watanabe 556cae7d9ecSWarner Losh static int 557cae7d9ecSWarner Losh acpi_uhub_get_device_path(device_t bus, device_t child, const char *locator, struct sbuf *sb) 558cae7d9ecSWarner Losh { 559cae7d9ecSWarner Losh if (strcmp(locator, BUS_LOCATOR_ACPI) == 0) 560cae7d9ecSWarner Losh return (acpi_get_acpi_device_path(bus, child, locator, sb)); 561cae7d9ecSWarner Losh 5629c750429SWarner Losh /* Otherwise call the parent class' method. */ 5639c750429SWarner Losh return (uhub_get_device_path(bus, child, locator, sb)); 564cae7d9ecSWarner Losh } 565cae7d9ecSWarner Losh 566e68fcc88STakanori Watanabe static device_method_t acpi_uhub_methods[] = { 567e68fcc88STakanori Watanabe DEVMETHOD(device_probe, acpi_uhub_probe), 568e68fcc88STakanori Watanabe DEVMETHOD(device_attach, acpi_uhub_attach), 569e68fcc88STakanori Watanabe DEVMETHOD(device_detach, acpi_uhub_detach), 570ddfc9c4cSWarner Losh DEVMETHOD(bus_child_location, acpi_uhub_child_location), 571cae7d9ecSWarner Losh DEVMETHOD(bus_get_device_path, acpi_uhub_get_device_path), 572e68fcc88STakanori Watanabe DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), 573e68fcc88STakanori Watanabe DEVMETHOD_END 574e68fcc88STakanori Watanabe 575e68fcc88STakanori Watanabe }; 576e68fcc88STakanori Watanabe 577e68fcc88STakanori Watanabe static device_method_t acpi_uhub_root_methods[] = { 578e68fcc88STakanori Watanabe DEVMETHOD(device_probe, acpi_uhub_root_probe), 579e68fcc88STakanori Watanabe DEVMETHOD(device_attach, acpi_uhub_root_attach), 580e68fcc88STakanori Watanabe DEVMETHOD(device_detach, acpi_uhub_detach), 581e68fcc88STakanori Watanabe DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), 582ddfc9c4cSWarner Losh DEVMETHOD(bus_child_location, acpi_uhub_child_location), 583cae7d9ecSWarner Losh DEVMETHOD(bus_get_device_path, acpi_uhub_get_device_path), 584e68fcc88STakanori Watanabe DEVMETHOD_END 585e68fcc88STakanori Watanabe }; 586e68fcc88STakanori Watanabe 587e68fcc88STakanori Watanabe extern driver_t uhub_driver; 588e68fcc88STakanori Watanabe static kobj_class_t uhub_baseclasses[] = {&uhub_driver, NULL}; 58974d565fdSHans Petter Selasky 590e68fcc88STakanori Watanabe static driver_t acpi_uhub_driver = { 591e68fcc88STakanori Watanabe .name = "uhub", 592e68fcc88STakanori Watanabe .methods = acpi_uhub_methods, 593e68fcc88STakanori Watanabe .size = sizeof(struct acpi_uhub_softc), 594e68fcc88STakanori Watanabe .baseclasses = uhub_baseclasses, 595e68fcc88STakanori Watanabe }; 59674d565fdSHans Petter Selasky 597e68fcc88STakanori Watanabe static driver_t acpi_uhub_root_driver = { 598e68fcc88STakanori Watanabe .name = "uhub", 599e68fcc88STakanori Watanabe .methods = acpi_uhub_root_methods, 600e68fcc88STakanori Watanabe .size = sizeof(struct acpi_uhub_softc), 601e68fcc88STakanori Watanabe .baseclasses = uhub_baseclasses, 602e68fcc88STakanori Watanabe }; 603e68fcc88STakanori Watanabe 604bc9372d7SJohn Baldwin DRIVER_MODULE(uacpi, uhub, acpi_uhub_driver, 0, 0); 605bc9372d7SJohn Baldwin DRIVER_MODULE(uacpi, usbus, acpi_uhub_root_driver, 0, 0); 6067fe671dcSHans Petter Selasky 6077fe671dcSHans Petter Selasky MODULE_DEPEND(uacpi, acpi, 1, 1, 1); 6087fe671dcSHans Petter Selasky MODULE_DEPEND(uacpi, usb, 1, 1, 1); 6097fe671dcSHans Petter Selasky 6107fe671dcSHans Petter Selasky MODULE_VERSION(uacpi, 1); 611