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> 82e68fcc88STakanori Watanabe 83e68fcc88STakanori Watanabe struct acpi_uhub_softc { 84e68fcc88STakanori Watanabe struct uhub_softc usc; 85e68fcc88STakanori Watanabe uint8_t nports; 86e68fcc88STakanori Watanabe ACPI_HANDLE *porthandle; 87e68fcc88STakanori Watanabe }; 88e68fcc88STakanori Watanabe 8974d565fdSHans Petter Selasky static UINT32 9074d565fdSHans Petter Selasky acpi_uhub_find_rh_cb(ACPI_HANDLE ah, UINT32 nl, void *ctx, void **status) 9174d565fdSHans Petter Selasky { 92e68fcc88STakanori Watanabe ACPI_DEVICE_INFO *devinfo; 9374d565fdSHans Petter Selasky UINT32 ret; 94e68fcc88STakanori Watanabe 95e68fcc88STakanori Watanabe *status = NULL; 96e68fcc88STakanori Watanabe devinfo = NULL; 97e68fcc88STakanori Watanabe 98e68fcc88STakanori Watanabe ret = AcpiGetObjectInfo(ah, &devinfo); 9974d565fdSHans Petter Selasky if (ACPI_SUCCESS(ret)) { 100e68fcc88STakanori Watanabe if ((devinfo->Valid & ACPI_VALID_ADR) && 101e68fcc88STakanori Watanabe (devinfo->Address == 0)) { 102e68fcc88STakanori Watanabe ret = AE_CTRL_TERMINATE; 103e68fcc88STakanori Watanabe *status = ah; 104e68fcc88STakanori Watanabe } 105e68fcc88STakanori Watanabe AcpiOsFree(devinfo); 10674d565fdSHans Petter Selasky } 10774d565fdSHans Petter Selasky return (ret); 108e68fcc88STakanori Watanabe } 109e68fcc88STakanori Watanabe 110e68fcc88STakanori Watanabe static int 111e68fcc88STakanori Watanabe acpi_uhub_parse_upc(device_t dev, unsigned int port, ACPI_HANDLE ah) 112e68fcc88STakanori Watanabe { 113e68fcc88STakanori Watanabe ACPI_BUFFER buf; 114e68fcc88STakanori Watanabe 115e68fcc88STakanori Watanabe buf.Pointer = NULL; 116e68fcc88STakanori Watanabe buf.Length = ACPI_ALLOCATE_BUFFER; 11774d565fdSHans Petter Selasky 118e68fcc88STakanori Watanabe if (AcpiEvaluateObject(ah, "_UPC", NULL, &buf) == AE_OK) { 119e68fcc88STakanori Watanabe UINT64 porttypenum, conn; 120e68fcc88STakanori Watanabe const char *connectable; 12174d565fdSHans Petter Selasky const char *typelist[] = { 12274d565fdSHans Petter Selasky "TypeA", "MiniAB", "Express", 123e68fcc88STakanori Watanabe "USB3-A", "USB3-B", "USB-MicroB", 124e68fcc88STakanori Watanabe "USB3-MicroAB", "USB3-PowerB", 125e68fcc88STakanori Watanabe "TypeC-USB2", "TypeC-Switch", 12674d565fdSHans Petter Selasky "TypeC-nonSwitch" 12774d565fdSHans Petter Selasky }; 128e68fcc88STakanori Watanabe const char *porttype; 129e68fcc88STakanori Watanabe const int last = sizeof(typelist) / sizeof(typelist[0]); 130e68fcc88STakanori Watanabe ACPI_OBJECT *obj = buf.Pointer; 131e68fcc88STakanori Watanabe 132e68fcc88STakanori Watanabe acpi_PkgInt(obj, 0, &conn); 133e68fcc88STakanori Watanabe acpi_PkgInt(obj, 1, &porttypenum); 134e68fcc88STakanori Watanabe connectable = conn ? "" : "non"; 135e68fcc88STakanori Watanabe if (porttypenum == 0xff) 136e68fcc88STakanori Watanabe porttype = "Proprietary"; 137e68fcc88STakanori Watanabe else if (porttypenum < last) { 138e68fcc88STakanori Watanabe porttype = typelist[porttypenum]; 139e68fcc88STakanori Watanabe } else { 140e68fcc88STakanori Watanabe porttype = "Unknown"; 141e68fcc88STakanori Watanabe } 142e68fcc88STakanori Watanabe if (usb_debug) 143e68fcc88STakanori Watanabe device_printf(dev, "Port %u %sconnectable %s\n", 144e68fcc88STakanori Watanabe port, connectable, porttype); 145e68fcc88STakanori Watanabe } 146e68fcc88STakanori Watanabe AcpiOsFree(buf.Pointer); 147e68fcc88STakanori Watanabe 14874d565fdSHans Petter Selasky return (0); 149e68fcc88STakanori Watanabe } 150e68fcc88STakanori Watanabe 151e68fcc88STakanori Watanabe static int 152e68fcc88STakanori Watanabe acpi_uhub_parse_pld(device_t dev, unsigned int port, ACPI_HANDLE ah) 153e68fcc88STakanori Watanabe { 154e68fcc88STakanori Watanabe ACPI_BUFFER buf; 155e68fcc88STakanori Watanabe 156e68fcc88STakanori Watanabe buf.Pointer = NULL; 157e68fcc88STakanori Watanabe buf.Length = ACPI_ALLOCATE_BUFFER; 15874d565fdSHans Petter Selasky 159e68fcc88STakanori Watanabe if (AcpiEvaluateObject(ah, "_PLD", NULL, &buf) == AE_OK) { 160e68fcc88STakanori Watanabe ACPI_OBJECT *obj; 161e68fcc88STakanori Watanabe unsigned char *resbuf; 162e68fcc88STakanori Watanabe int len; 163e68fcc88STakanori Watanabe 164e68fcc88STakanori Watanabe obj = buf.Pointer; 165e68fcc88STakanori Watanabe 166e68fcc88STakanori Watanabe if (obj->Type == ACPI_TYPE_PACKAGE 167e68fcc88STakanori Watanabe && obj->Package.Elements[0].Type == ACPI_TYPE_BUFFER) { 168e68fcc88STakanori Watanabe ACPI_OBJECT *obj1; 169e68fcc88STakanori Watanabe 170e68fcc88STakanori Watanabe obj1 = &obj->Package.Elements[0]; 171e68fcc88STakanori Watanabe len = obj1->Buffer.Length; 172e68fcc88STakanori Watanabe resbuf = obj1->Buffer.Pointer; 173e68fcc88STakanori Watanabe } else if (obj->Type == ACPI_TYPE_BUFFER) { 174e68fcc88STakanori Watanabe len = obj->Buffer.Length; 175e68fcc88STakanori Watanabe resbuf = obj->Buffer.Pointer; 176e68fcc88STakanori Watanabe } else { 177e68fcc88STakanori Watanabe goto skip; 178e68fcc88STakanori Watanabe } 179e68fcc88STakanori Watanabe if (usb_debug) { 180e68fcc88STakanori Watanabe device_printf(dev, "Revision:%d\n", 181e68fcc88STakanori Watanabe resbuf[0] & 0x7f); 182e68fcc88STakanori Watanabe if ((resbuf[0] & 0x80) == 0) { 183e68fcc88STakanori Watanabe device_printf(dev, 184e68fcc88STakanori Watanabe "Color:#%02x%02x%02x\n", 185e68fcc88STakanori Watanabe resbuf[1], resbuf[2], 186e68fcc88STakanori Watanabe resbuf[3]); 187e68fcc88STakanori Watanabe } 188e68fcc88STakanori Watanabe device_printf(dev, "Width %d mm Height %d mm\n", 189e68fcc88STakanori Watanabe resbuf[4] | (resbuf[5] << 8), 190e68fcc88STakanori Watanabe resbuf[6] | (resbuf[7] << 8)); 191e68fcc88STakanori Watanabe if (resbuf[8] & 1) { 192e68fcc88STakanori Watanabe device_printf(dev, "Visible\n"); 193e68fcc88STakanori Watanabe } 194e68fcc88STakanori Watanabe if (resbuf[8] & 2) { 195e68fcc88STakanori Watanabe device_printf(dev, "Dock\n"); 196e68fcc88STakanori Watanabe } 197e68fcc88STakanori Watanabe if (resbuf[8] & 4) { 198e68fcc88STakanori Watanabe device_printf(dev, "Lid\n"); 199e68fcc88STakanori Watanabe } 200e68fcc88STakanori Watanabe device_printf(dev, "PanelPosition: %d\n", 201e68fcc88STakanori Watanabe (resbuf[8] >> 3) & 7); 202e68fcc88STakanori Watanabe device_printf(dev, "VertPosition: %d\n", 203e68fcc88STakanori Watanabe (resbuf[8] >> 6) & 3); 204e68fcc88STakanori Watanabe device_printf(dev, "HorizPosition: %d\n", 205e68fcc88STakanori Watanabe (resbuf[9]) & 3); 206e68fcc88STakanori Watanabe device_printf(dev, "Shape: %d\n", 207e68fcc88STakanori Watanabe (resbuf[9] >> 2) & 0xf); 208e68fcc88STakanori Watanabe device_printf(dev, "80: %02x, %02x, %02x\n", 209e68fcc88STakanori Watanabe resbuf[9], resbuf[10], resbuf[11]); 210e68fcc88STakanori Watanabe device_printf(dev, "96: %02x, %02x, %02x, %02x\n", 211e68fcc88STakanori Watanabe resbuf[12], resbuf[13], 212e68fcc88STakanori Watanabe resbuf[14], resbuf[15]); 213e68fcc88STakanori Watanabe 214e68fcc88STakanori Watanabe if ((resbuf[0] & 0x7f) >= 2) { 215e68fcc88STakanori Watanabe device_printf(dev, "VOFF%d mm HOFF %dmm", 216e68fcc88STakanori Watanabe resbuf[16] | (resbuf[17] << 8), 217e68fcc88STakanori Watanabe resbuf[18] | (resbuf[19] << 8)); 218e68fcc88STakanori Watanabe } 219e68fcc88STakanori Watanabe } 220e68fcc88STakanori Watanabe skip: 221e68fcc88STakanori Watanabe AcpiOsFree(buf.Pointer); 22274d565fdSHans Petter Selasky } 22374d565fdSHans Petter Selasky return (0); 224e68fcc88STakanori Watanabe } 225e68fcc88STakanori Watanabe 22674d565fdSHans Petter Selasky static ACPI_STATUS 227a809abd4STakanori Watanabe acpi_uhub_find_rh(device_t dev, ACPI_HANDLE *ah) 228a809abd4STakanori Watanabe { 229e68fcc88STakanori Watanabe device_t grand; 230e68fcc88STakanori Watanabe ACPI_HANDLE gah; 231e68fcc88STakanori Watanabe 232a809abd4STakanori Watanabe *ah = NULL; 233e68fcc88STakanori Watanabe grand = device_get_parent(device_get_parent(dev)); 23474d565fdSHans Petter Selasky 23574d565fdSHans Petter Selasky if ((gah = acpi_get_handle(grand)) == NULL) 23674d565fdSHans Petter Selasky return (AE_ERROR); 23774d565fdSHans Petter Selasky 23874d565fdSHans Petter Selasky return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1, 23974d565fdSHans Petter Selasky acpi_uhub_find_rh_cb, NULL, dev, ah)); 240e68fcc88STakanori Watanabe } 241e68fcc88STakanori Watanabe 24274d565fdSHans Petter Selasky static ACPI_STATUS 243a809abd4STakanori Watanabe acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv) 244a809abd4STakanori Watanabe { 245e68fcc88STakanori Watanabe ACPI_DEVICE_INFO *devinfo; 246e68fcc88STakanori Watanabe device_t dev = ctx; 247e68fcc88STakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 24874d565fdSHans Petter Selasky UINT32 ret; 249e68fcc88STakanori Watanabe 25074d565fdSHans Petter Selasky ret = AcpiGetObjectInfo(ah, &devinfo); 25174d565fdSHans Petter Selasky if (ACPI_SUCCESS(ret)) { 252e68fcc88STakanori Watanabe if ((devinfo->Valid & ACPI_VALID_ADR) && 253e68fcc88STakanori Watanabe (devinfo->Address > 0) && 254e68fcc88STakanori Watanabe (devinfo->Address <= (uint64_t)sc->nports)) { 255e68fcc88STakanori Watanabe sc->porthandle[devinfo->Address - 1] = ah; 256e68fcc88STakanori Watanabe acpi_uhub_parse_upc(dev, devinfo->Address, ah); 257e68fcc88STakanori Watanabe acpi_uhub_parse_pld(dev, devinfo->Address, ah); 258e68fcc88STakanori Watanabe } 259e68fcc88STakanori Watanabe AcpiOsFree(devinfo); 26074d565fdSHans Petter Selasky } 26174d565fdSHans Petter Selasky return (AE_OK); 262e68fcc88STakanori Watanabe } 263e68fcc88STakanori Watanabe 26474d565fdSHans Petter Selasky static ACPI_STATUS 265a809abd4STakanori Watanabe acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah) 266a809abd4STakanori Watanabe { 26774d565fdSHans Petter Selasky return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, 268e68fcc88STakanori Watanabe ah, 1, 269e68fcc88STakanori Watanabe acpi_usb_hub_port_probe_cb, 27074d565fdSHans Petter Selasky NULL, dev, NULL)); 271e68fcc88STakanori Watanabe } 27274d565fdSHans Petter Selasky 27374d565fdSHans Petter Selasky static int 274e68fcc88STakanori Watanabe acpi_uhub_root_probe(device_t dev) 275e68fcc88STakanori Watanabe { 276e68fcc88STakanori Watanabe ACPI_STATUS status; 27774d565fdSHans Petter Selasky ACPI_HANDLE ah; 278e68fcc88STakanori Watanabe 27974d565fdSHans Petter Selasky if (acpi_disabled("usb")) 28074d565fdSHans Petter Selasky return (ENXIO); 28174d565fdSHans Petter Selasky 282e68fcc88STakanori Watanabe status = acpi_uhub_find_rh(dev, &ah); 28374d565fdSHans Petter Selasky if (ACPI_SUCCESS(status) && ah != NULL && 28474d565fdSHans Petter Selasky uhub_probe(dev) <= 0) { 28574d565fdSHans Petter Selasky /* success prior than non-ACPI USB HUB */ 286e68fcc88STakanori Watanabe return (BUS_PROBE_DEFAULT + 1); 287e68fcc88STakanori Watanabe } 288e68fcc88STakanori Watanabe return (ENXIO); 289e68fcc88STakanori Watanabe } 29074d565fdSHans Petter Selasky 29174d565fdSHans Petter Selasky static int 29274d565fdSHans Petter Selasky acpi_uhub_probe(device_t dev) 29374d565fdSHans Petter Selasky { 29474d565fdSHans Petter Selasky ACPI_HANDLE ah; 29574d565fdSHans Petter Selasky 29674d565fdSHans Petter Selasky if (acpi_disabled("usb")) 29774d565fdSHans Petter Selasky return (ENXIO); 29874d565fdSHans Petter Selasky 29974d565fdSHans Petter Selasky ah = acpi_get_handle(dev); 30074d565fdSHans Petter Selasky if (ah == NULL) 30174d565fdSHans Petter Selasky return (ENXIO); 30274d565fdSHans Petter Selasky 30374d565fdSHans Petter Selasky if (uhub_probe(dev) <= 0) { 30474d565fdSHans Petter Selasky /* success prior than non-ACPI USB HUB */ 30574d565fdSHans Petter Selasky return (BUS_PROBE_DEFAULT + 1); 30674d565fdSHans Petter Selasky } 30774d565fdSHans Petter Selasky return (ENXIO); 30874d565fdSHans Petter Selasky } 30974d565fdSHans Petter Selasky 31074d565fdSHans Petter Selasky static int 311e68fcc88STakanori Watanabe acpi_uhub_root_attach(device_t dev) 312e68fcc88STakanori Watanabe { 313e68fcc88STakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 31474d565fdSHans Petter Selasky ACPI_STATUS status; 31574d565fdSHans Petter Selasky ACPI_HANDLE ah; 316e68fcc88STakanori Watanabe int ret; 317e68fcc88STakanori Watanabe 31874d565fdSHans Petter Selasky ret = uhub_attach(dev); 31974d565fdSHans Petter Selasky if (ret != 0) 32074d565fdSHans Petter Selasky goto done; 321e68fcc88STakanori Watanabe 32274d565fdSHans Petter Selasky status = acpi_uhub_find_rh(dev, &ah); 32374d565fdSHans Petter Selasky if (ACPI_SUCCESS(status) && ah != NULL) { 32474d565fdSHans Petter Selasky struct usb_hub *uh = sc->usc.sc_udev->hub; 325e68fcc88STakanori Watanabe 326e68fcc88STakanori Watanabe sc->nports = uh->nports; 327e68fcc88STakanori Watanabe sc->porthandle = malloc(sizeof(ACPI_HANDLE) * uh->nports, 328e68fcc88STakanori Watanabe M_USBDEV, M_WAITOK | M_ZERO); 32974d565fdSHans Petter Selasky acpi_usb_hub_port_probe(dev, ah); 33074d565fdSHans Petter Selasky } 33174d565fdSHans Petter Selasky done: 33274d565fdSHans Petter Selasky return (ret); 333e68fcc88STakanori Watanabe } 334e68fcc88STakanori Watanabe 33574d565fdSHans Petter Selasky static int 336e68fcc88STakanori Watanabe acpi_uhub_attach(device_t dev) 337e68fcc88STakanori Watanabe { 338e68fcc88STakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 33974d565fdSHans Petter Selasky ACPI_HANDLE ah; 340e68fcc88STakanori Watanabe int ret; 341e68fcc88STakanori Watanabe 34274d565fdSHans Petter Selasky ret = uhub_attach(dev); 34374d565fdSHans Petter Selasky if (ret != 0) 34474d565fdSHans Petter Selasky goto done; 345e68fcc88STakanori Watanabe 34674d565fdSHans Petter Selasky ah = acpi_get_handle(dev); 34774d565fdSHans Petter Selasky if (ah != NULL) { 34874d565fdSHans Petter Selasky struct usb_hub *uh = sc->usc.sc_udev->hub; 349e68fcc88STakanori Watanabe 350e68fcc88STakanori Watanabe sc->nports = uh->nports; 351e68fcc88STakanori Watanabe sc->porthandle = malloc(sizeof(ACPI_HANDLE) * uh->nports, 352e68fcc88STakanori Watanabe M_USBDEV, M_WAITOK | M_ZERO); 35374d565fdSHans Petter Selasky acpi_usb_hub_port_probe(dev, ah); 35474d565fdSHans Petter Selasky } 35574d565fdSHans Petter Selasky done: 35674d565fdSHans Petter Selasky return (ret); 357e68fcc88STakanori Watanabe } 358e68fcc88STakanori Watanabe 35974d565fdSHans Petter Selasky static int 36074d565fdSHans Petter Selasky acpi_uhub_read_ivar(device_t dev, device_t child, int idx, uintptr_t *res) 361e68fcc88STakanori Watanabe { 362e68fcc88STakanori Watanabe struct hub_result hres; 363e68fcc88STakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 364e68fcc88STakanori Watanabe ACPI_HANDLE ah; 365e68fcc88STakanori Watanabe 366e68fcc88STakanori Watanabe mtx_lock(&Giant); 367e68fcc88STakanori Watanabe uhub_find_iface_index(sc->usc.sc_udev->hub, child, &hres); 368e68fcc88STakanori Watanabe mtx_unlock(&Giant); 36974d565fdSHans Petter Selasky 370e68fcc88STakanori Watanabe if ((idx == ACPI_IVAR_HANDLE) && 371e68fcc88STakanori Watanabe (hres.portno > 0) && 372e68fcc88STakanori Watanabe (hres.portno <= sc->nports) && 373e68fcc88STakanori Watanabe (ah = sc->porthandle[hres.portno - 1])) { 374e68fcc88STakanori Watanabe *res = (uintptr_t)ah; 375e68fcc88STakanori Watanabe return (0); 376e68fcc88STakanori Watanabe } 377e68fcc88STakanori Watanabe return (ENXIO); 378e68fcc88STakanori Watanabe } 37974d565fdSHans Petter Selasky 380e68fcc88STakanori Watanabe static int 381e68fcc88STakanori Watanabe acpi_uhub_child_location_string(device_t parent, device_t child, 382e68fcc88STakanori Watanabe char *buf, size_t buflen) 383e68fcc88STakanori Watanabe { 384e68fcc88STakanori Watanabe ACPI_HANDLE ah; 385e68fcc88STakanori Watanabe 386e68fcc88STakanori Watanabe uhub_child_location_string(parent, child, buf, buflen); 38774d565fdSHans Petter Selasky 388e68fcc88STakanori Watanabe ah = acpi_get_handle(child); 38974d565fdSHans Petter Selasky if (ah != NULL) { 390e68fcc88STakanori Watanabe strlcat(buf, " handle=", buflen); 391e68fcc88STakanori Watanabe strlcat(buf, acpi_name(ah), buflen); 392e68fcc88STakanori Watanabe } 393e68fcc88STakanori Watanabe return (0); 394e68fcc88STakanori Watanabe } 395e68fcc88STakanori Watanabe 39674d565fdSHans Petter Selasky static int 397e68fcc88STakanori Watanabe acpi_uhub_detach(device_t dev) 398e68fcc88STakanori Watanabe { 399e68fcc88STakanori Watanabe struct acpi_uhub_softc *sc = device_get_softc(dev); 400e68fcc88STakanori Watanabe 401e68fcc88STakanori Watanabe free(sc->porthandle, M_USBDEV); 40274d565fdSHans Petter Selasky 40374d565fdSHans Petter Selasky return (uhub_detach(dev)); 404e68fcc88STakanori Watanabe } 405e68fcc88STakanori Watanabe 406e68fcc88STakanori Watanabe static device_method_t acpi_uhub_methods[] = { 407e68fcc88STakanori Watanabe DEVMETHOD(device_probe, acpi_uhub_probe), 408e68fcc88STakanori Watanabe DEVMETHOD(device_attach, acpi_uhub_attach), 409e68fcc88STakanori Watanabe DEVMETHOD(device_detach, acpi_uhub_detach), 410e68fcc88STakanori Watanabe DEVMETHOD(bus_child_location_str, acpi_uhub_child_location_string), 411e68fcc88STakanori Watanabe DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), 412e68fcc88STakanori Watanabe DEVMETHOD_END 413e68fcc88STakanori Watanabe 414e68fcc88STakanori Watanabe }; 415e68fcc88STakanori Watanabe 416e68fcc88STakanori Watanabe static device_method_t acpi_uhub_root_methods[] = { 417e68fcc88STakanori Watanabe DEVMETHOD(device_probe, acpi_uhub_root_probe), 418e68fcc88STakanori Watanabe DEVMETHOD(device_attach, acpi_uhub_root_attach), 419e68fcc88STakanori Watanabe DEVMETHOD(device_detach, acpi_uhub_detach), 420e68fcc88STakanori Watanabe DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), 421e68fcc88STakanori Watanabe DEVMETHOD(bus_child_location_str, acpi_uhub_child_location_string), 422e68fcc88STakanori Watanabe DEVMETHOD_END 423e68fcc88STakanori Watanabe }; 424e68fcc88STakanori Watanabe 425e68fcc88STakanori Watanabe static devclass_t uhub_devclass; 426e68fcc88STakanori Watanabe extern driver_t uhub_driver; 427e68fcc88STakanori Watanabe static kobj_class_t uhub_baseclasses[] = {&uhub_driver, NULL}; 42874d565fdSHans Petter Selasky 429e68fcc88STakanori Watanabe static driver_t acpi_uhub_driver = { 430e68fcc88STakanori Watanabe .name = "uhub", 431e68fcc88STakanori Watanabe .methods = acpi_uhub_methods, 432e68fcc88STakanori Watanabe .size = sizeof(struct acpi_uhub_softc), 433e68fcc88STakanori Watanabe .baseclasses = uhub_baseclasses, 434e68fcc88STakanori Watanabe }; 43574d565fdSHans Petter Selasky 436e68fcc88STakanori Watanabe static driver_t acpi_uhub_root_driver = { 437e68fcc88STakanori Watanabe .name = "uhub", 438e68fcc88STakanori Watanabe .methods = acpi_uhub_root_methods, 439e68fcc88STakanori Watanabe .size = sizeof(struct acpi_uhub_softc), 440e68fcc88STakanori Watanabe .baseclasses = uhub_baseclasses, 441e68fcc88STakanori Watanabe }; 442e68fcc88STakanori Watanabe 443*7fe671dcSHans Petter Selasky DRIVER_MODULE(uacpi, uhub, acpi_uhub_driver, uhub_devclass, 0, 0); 444*7fe671dcSHans Petter Selasky DRIVER_MODULE(uacpi, usbus, acpi_uhub_root_driver, uhub_devclass, 0, 0); 445*7fe671dcSHans Petter Selasky 446*7fe671dcSHans Petter Selasky MODULE_DEPEND(uacpi, acpi, 1, 1, 1); 447*7fe671dcSHans Petter Selasky MODULE_DEPEND(uacpi, usb, 1, 1, 1); 448*7fe671dcSHans Petter Selasky 449*7fe671dcSHans Petter Selasky MODULE_VERSION(uacpi, 1); 450