Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -3234,6 +3234,7 @@ dev/usb/usb_handle_request.c optional usb dev/usb/usb_hid.c optional usb dev/usb/usb_hub.c optional usb +dev/usb/usb_hub_acpi.c optional usb acpi dev/usb/usb_if.m optional usb dev/usb/usb_lookup.c optional usb dev/usb/usb_mbuf.c optional usb Index: sys/dev/usb/usb_hub.c =================================================================== --- sys/dev/usb/usb_hub.c +++ sys/dev/usb/usb_hub.c @@ -75,15 +75,10 @@ #include #endif /* USB_GLOBAL_INCLUDE_FILE */ -#define UHUB_INTR_INTERVAL 250 /* ms */ -enum { - UHUB_INTR_TRANSFER, -#if USB_HAVE_TT_SUPPORT - UHUB_RESET_TT_TRANSFER, -#endif - UHUB_N_TRANSFER, -}; +#include + + #ifdef USB_DEBUG static int uhub_debug = 0; @@ -111,30 +106,7 @@ &usb_disable_port_power, 0, "Set to disable all USB port power."); #endif -struct uhub_current_state { - uint16_t port_change; - uint16_t port_status; -}; -struct uhub_softc { - struct uhub_current_state sc_st;/* current state */ -#if (USB_HAVE_FIXED_PORT != 0) - struct usb_hub sc_hub; -#endif - device_t sc_dev; /* base device */ - struct mtx sc_mtx; /* our mutex */ - struct usb_device *sc_udev; /* USB device */ - struct usb_xfer *sc_xfer[UHUB_N_TRANSFER]; /* interrupt xfer */ -#if USB_HAVE_DISABLE_ENUM - int sc_disable_enumeration; - int sc_disable_port_power; -#endif - uint8_t sc_usb_port_errors; /* error counter */ -#define UHUB_USB_PORT_ERRORS_MAX 4 - uint8_t sc_flags; -#define UHUB_FLAG_DID_EXPLORE 0x01 -}; - #define UHUB_PROTO(sc) ((sc)->sc_udev->ddesc.bDeviceProtocol) #define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB) #define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT) @@ -143,14 +115,10 @@ /* prototypes for type checking: */ -static device_probe_t uhub_probe; -static device_attach_t uhub_attach; -static device_detach_t uhub_detach; static device_suspend_t uhub_suspend; static device_resume_t uhub_resume; static bus_driver_added_t uhub_driver_added; -static bus_child_location_str_t uhub_child_location_string; static bus_child_pnpinfo_str_t uhub_child_pnpinfo_string; static usb_callback_t uhub_intr_callback; @@ -207,7 +175,7 @@ DEVMETHOD_END }; -static driver_t uhub_driver = { +driver_t uhub_driver = { .name = "uhub", .methods = uhub_methods, .size = sizeof(struct uhub_softc) @@ -1138,7 +1106,7 @@ return (USB_ERR_NORMAL_COMPLETION); } -static int +int uhub_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); @@ -1152,7 +1120,7 @@ */ if (uaa->info.bConfigIndex == 0 && uaa->info.bDeviceClass == UDCLASS_HUB) - return (0); + return (BUS_PROBE_DEFAULT); return (ENXIO); } @@ -1218,7 +1186,7 @@ return (err); } -static int +int uhub_attach(device_t dev) { struct uhub_softc *sc = device_get_softc(dev); @@ -1564,7 +1532,7 @@ * Called from process context when the hub is gone. * Detach all devices on active ports. */ -static int +int uhub_detach(device_t dev) { struct uhub_softc *sc = device_get_softc(dev); @@ -1634,13 +1602,7 @@ usb_needs_explore_all(); } -struct hub_result { - struct usb_device *udev; - uint8_t portno; - uint8_t iface_index; -}; - -static void +void uhub_find_iface_index(struct usb_hub *hub, device_t child, struct hub_result *res) { @@ -1673,7 +1635,7 @@ res->portno = 0; } -static int +int uhub_child_location_string(device_t parent, device_t child, char *buf, size_t buflen) { Index: sys/dev/usb/usb_hub_acpi.c =================================================================== --- /dev/null +++ sys/dev/usb/usb_hub_acpi.c @@ -0,0 +1,431 @@ +/* $FreeBSD$ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause-NetBSD + * + * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. + * Copyright (c) 1998 Lennart Augustsson. All rights reserved. + * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2019 Takanori Watanabe. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * USB spec: http://www.usb.org/developers/docs/usbspec.zip + */ + +#ifdef USB_GLOBAL_INCLUDE_FILE +#include USB_GLOBAL_INCLUDE_FILE +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define USB_DEBUG_VAR uhub_debug + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#endif /* USB_GLOBAL_INCLUDE_FILE */ + + +#include +#include +#include +#include +static UINT32 acpi_uhub_find_rh_cb(ACPI_HANDLE ah, UINT32 nl, void *ctx, void **status); +static ACPI_STATUS acpi_uhub_find_rh(device_t dev, ACPI_HANDLE *ah); +static ACPI_STATUS +acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv); +static ACPI_STATUS acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah); +static int acpi_uhub_root_probe(device_t dev); +static int acpi_uhub_probe(device_t dev); +static int acpi_uhub_root_attach(device_t dev); +static int acpi_uhub_attach(device_t dev); +static int acpi_uhub_detach(device_t dev); +static int acpi_uhub_read_ivar(device_t dev, device_t child, int idx, + uintptr_t *res); +static int acpi_uhub_child_location_string(device_t parent, device_t child, + char *buf, size_t buflen); +static int acpi_uhub_parse_upc(device_t dev, unsigned int port , ACPI_HANDLE ah); + +struct acpi_uhub_softc { + struct uhub_softc usc; + int nports; + ACPI_HANDLE *porthandle; +}; + +UINT32 acpi_uhub_find_rh_cb(ACPI_HANDLE ah, UINT32 nl, void *ctx, void **status) +{ + ACPI_DEVICE_INFO *devinfo; + UINT32 ret = AE_OK; + //device_t dev = ctx; + + *status = NULL; + devinfo = NULL; + + ret =AcpiGetObjectInfo(ah, &devinfo); + + if(ACPI_FAILURE(ret)) + { + printf("Error %d\n", ret); + return ret; + } + if((devinfo->Valid & ACPI_VALID_ADR) && + (devinfo->Address == 0)){ + // Found + ret = AE_CTRL_TERMINATE; + *status = ah; + } + AcpiOsFree(devinfo); + + return ret; +} +static int acpi_uhub_parse_upc(device_t dev, unsigned int port, ACPI_HANDLE ah) +{ + ACPI_BUFFER buf; + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_BUFFER; + if(AcpiEvaluateObject(ah, "_UPC", NULL, &buf) == AE_OK) + { + UINT64 porttypenum, conn; + const char *connectable ; + const char *typelist[] = {"TypeA", "MiniAB", "Express", + "USB3-A", "USB3-B", "USB-MicroB", + "USB3-MicroAB", "USB3-PowerB", + "TypeC-USB2", "TypeC-Switch", + "TypeC-nonSwitch"}; + const char *porttype; + const int last = sizeof(typelist)/sizeof(typelist[0]); + ACPI_OBJECT *obj = buf.Pointer; + acpi_PkgInt(obj, 0, &conn); + acpi_PkgInt(obj, 1, &porttypenum); + connectable = conn ? "" : "non"; + if(porttypenum == 0xff) + porttype = "Proprieary"; + else if(porttypenum < last) { + porttype = typelist[porttypenum]; + }else{ + porttype = "Unknown"; + } + device_printf(dev, "Port %u %sconnectable %s\n", port, + connectable, porttype); + } + AcpiOsFree(buf.Pointer); + + return 0; +} +static int acpi_uhub_parse_pld(device_t dev, unsigned int port, ACPI_HANDLE ah) +{ + ACPI_BUFFER buf; + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_BUFFER; + if(AcpiEvaluateObject(ah, "_PLD", NULL, &buf) == AE_OK) + { + ACPI_OBJECT *obj; + unsigned char *resbuf; + obj = buf.Pointer; + int len; + int i; + if(obj->Type == ACPI_TYPE_PACKAGE + && obj->Package.Elements[0].Type == ACPI_TYPE_BUFFER){ + ACPI_OBJECT *obj1; + obj1 = &obj->Package.Elements[0]; + device_printf(dev, "%d %d\n", obj1->Type, obj1->Buffer.Length); + len = obj1->Buffer.Length; + resbuf = obj1->Buffer.Pointer; + }else if(obj->Type == ACPI_TYPE_BUFFER){ + len = obj->Buffer.Length; + resbuf = obj->Buffer.Pointer; + }else{ + goto skip; + } + for(i = 0; i< len ; i++){ + printf("%02x ", resbuf[i]); + } + device_printf(dev, "Revision:%d\n", resbuf[0]& 0x7f); + if((resbuf[0]&0x80) == 0){ + device_printf(dev, "Color:#%02x%02x%02x\n", + resbuf[1], resbuf[2], resbuf[3]); + } + device_printf( dev, "Width %d mm Height %d mm\n", resbuf[4]|(resbuf[5]<<8), resbuf[6]|(resbuf[7]<<8)); + if(resbuf[8]&1){ + device_printf(dev, "Visible\n"); + } + if(resbuf[8]&2){ + device_printf(dev, "Dock\n"); + } + if(resbuf[8]&4){ + device_printf(dev, "Lid\n"); + } + device_printf(dev, "PanelPosition: %d\n", (resbuf[8]>>3)&7); + device_printf(dev, "VertPosition: %d\n", (resbuf[8]>>6)&3); + device_printf(dev, "HorizPosition: %d\n", (resbuf[9])&3); + device_printf(dev, "Shape: %d\n", (resbuf[9]>>2)&0xf); + device_printf(dev, "80: %02x, %02x, %02x\n", + resbuf[9], resbuf[10], resbuf[11]); + device_printf(dev, "96: %02x, %02x, %02x, %02x\n", + resbuf[12], resbuf[13], resbuf[14], resbuf[15]); + + if((resbuf[0]&0x7f) >= 2){ + device_printf(dev, "VOFF%d mm HOFF %dmm", + resbuf[16]|(resbuf[17]<<8), + resbuf[18]|(resbuf[19]<<8)); + } + skip: + AcpiOsFree(buf.Pointer); + } + + + return 0; +} + +ACPI_STATUS acpi_uhub_find_rh(device_t dev, ACPI_HANDLE *ah) +{ + device_t grand; + ACPI_HANDLE gah; + grand = device_get_parent(device_get_parent(dev)); + if((gah = acpi_get_handle(grand)) == NULL){ + *ah = NULL; + return AE_ERROR; + } + return AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1, + acpi_uhub_find_rh_cb, NULL, dev, ah); +} + +ACPI_STATUS +acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv) +{ + ACPI_DEVICE_INFO *devinfo; + device_t dev = ctx; + struct acpi_uhub_softc *sc = device_get_softc(dev); + device_printf(dev, "%s\n", acpi_name(ah)); + AcpiGetObjectInfo(ah, &devinfo); + if((devinfo->Valid & ACPI_VALID_ADR)&& + (devinfo->Address > 0) && + (devinfo->Address <= sc->nports)){ + sc->porthandle[devinfo->Address] = ah; + acpi_uhub_parse_upc(dev, devinfo->Address, ah); + acpi_uhub_parse_pld(dev, devinfo->Address, ah); + }else{ + device_printf(dev, "Skiping invalid devobj %s\n", + acpi_name(ah)); + } + AcpiOsFree(devinfo); + return AE_OK; +} + +ACPI_STATUS acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah) +{ + device_printf(dev, "PORT PROBE\n"); + return AcpiWalkNamespace(ACPI_TYPE_DEVICE, + ah, 1, + acpi_usb_hub_port_probe_cb, + NULL, dev, NULL); +} +int acpi_uhub_root_probe(device_t dev) +{ + ACPI_HANDLE ah; + ACPI_STATUS status; + + status = acpi_uhub_find_rh(dev, &ah); + if(ACPI_SUCCESS(status) + &&ah != NULL + && (uhub_probe(dev) <= 0)){ + printf("ACPI UHUB FOUND\n"); + // success prior than non-acpi hub + return (BUS_PROBE_DEFAULT + 1); + } + return ENXIO; +} + +int acpi_uhub_probe(device_t dev) +{ + ACPI_HANDLE ah = acpi_get_handle(dev); + if(ah && (uhub_probe(dev)<=0)){ + // success prior than non-acpi hub + return (BUS_PROBE_DEFAULT + 1); + } + return (ENXIO); +} +int acpi_uhub_root_attach(device_t dev) +{ + ACPI_HANDLE devhandle; + struct usb_hub *uh; + struct acpi_uhub_softc *sc = device_get_softc(dev); + int ret; + printf("ROOTHUB_ATTACH\n"); + + if((ret= uhub_attach(dev)) != 0){ + return(ret); + } + uh = sc->usc.sc_udev->hub; + + if(ACPI_FAILURE(acpi_uhub_find_rh(dev, &devhandle))|| + (devhandle == NULL)){ + return ENXIO; + } + + sc->nports = uh->nports; + sc->porthandle = malloc(sizeof(ACPI_HANDLE)*uh->nports, + M_USBDEV, M_WAITOK | M_ZERO); + acpi_uhub_find_rh(dev, &devhandle); + acpi_usb_hub_port_probe(dev, devhandle); + + return 0; +} + +int acpi_uhub_attach(device_t dev) +{ + struct usb_hub *uh; + struct acpi_uhub_softc *sc = device_get_softc(dev); + ACPI_HANDLE devhandle; + int ret; + device_printf(dev, "UHUB ATTACH\n"); + if((ret= uhub_attach(dev)) != 0){ + return(ret); + } + uh = sc->usc.sc_udev->hub; + devhandle = acpi_get_handle(dev); + + if(devhandle == NULL){ + return ENXIO; + } + + sc->nports = uh->nports; + sc->porthandle = malloc(sizeof(ACPI_HANDLE)*uh->nports, + M_USBDEV, M_WAITOK | M_ZERO); + acpi_usb_hub_port_probe(dev, acpi_get_handle(dev)); + return 0; +} + +int acpi_uhub_read_ivar(device_t dev, device_t child, int idx, + uintptr_t *res) +{ + struct hub_result hres; + struct acpi_uhub_softc *sc = device_get_softc(dev); + ACPI_HANDLE ah; + mtx_lock(&Giant); + uhub_find_iface_index(sc->usc.sc_udev->hub, child, &hres); + mtx_unlock(&Giant); + if((idx == ACPI_IVAR_HANDLE)&& + (hres.portno > 0)&& + (hres.portno <= sc->nports)&& + (ah = sc->porthandle[hres.portno -1])){ + *res = (uintptr_t)ah; + return (0); + } + return (ENXIO); +} +static int acpi_uhub_child_location_string(device_t parent, device_t child, + char *buf, size_t buflen) +{ + + ACPI_HANDLE ah; + uhub_child_location_string(parent, child, buf, buflen); + ah = acpi_get_handle(child); + if(ah){ + strlcat(buf, " handle=", buflen); + strlcat(buf, acpi_name(ah), buflen); + } + return (0); +} + +int acpi_uhub_detach(device_t dev) +{ + struct acpi_uhub_softc *sc = device_get_softc(dev); + + free(sc->porthandle, M_USBDEV); + return uhub_detach(dev); +} + +static device_method_t acpi_uhub_methods[] = { + DEVMETHOD(device_probe, acpi_uhub_probe), + DEVMETHOD(device_attach, acpi_uhub_attach), + DEVMETHOD(device_detach, acpi_uhub_detach), + + DEVMETHOD(bus_child_location_str,acpi_uhub_child_location_string), + DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), + DEVMETHOD_END + +}; + +static device_method_t acpi_uhub_root_methods[] = { + DEVMETHOD(device_probe, acpi_uhub_root_probe), + DEVMETHOD(device_attach, acpi_uhub_root_attach), + DEVMETHOD(device_detach, acpi_uhub_detach), + + DEVMETHOD(bus_read_ivar, acpi_uhub_read_ivar), + DEVMETHOD(bus_child_location_str,acpi_uhub_child_location_string), + DEVMETHOD_END +}; + +static devclass_t uhub_devclass; +extern driver_t uhub_driver; +static kobj_class_t uhub_baseclasses[] = {&uhub_driver, NULL}; +static driver_t acpi_uhub_driver ={ + .name = "uhub", + .methods = acpi_uhub_methods, + .size = sizeof(struct acpi_uhub_softc), + .baseclasses = uhub_baseclasses, +}; +static driver_t acpi_uhub_root_driver ={ + .name = "uhub", + .methods = acpi_uhub_root_methods, + .size = sizeof(struct acpi_uhub_softc), + .baseclasses = uhub_baseclasses, +}; + + +DRIVER_MODULE(acpi_uhub, uhub, acpi_uhub_driver, uhub_devclass, 0, 0); +MODULE_DEPEND(acpi_uhub, acpi, 1, 1, 1); +DRIVER_MODULE(acpi_uhub, usbus, acpi_uhub_root_driver, uhub_devclass, 0, 0); + Index: sys/dev/usb/usb_hub_private.h =================================================================== --- /dev/null +++ sys/dev/usb/usb_hub_private.h @@ -0,0 +1,84 @@ +/* $FreeBSD$ */ +/*- + * SPDX-License-Identifier: BSD-2-Clause-NetBSD + * + * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. + * Copyright (c) 1998 Lennart Augustsson. All rights reserved. + * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * USB spec: http://www.usb.org/developers/docs/usbspec.zip + */ + +#ifndef USB_HUB_PRIVATE_H_ +#define USB_HUB_PRIVATE_H_ +#define UHUB_INTR_INTERVAL 250 /* ms */ +enum { + UHUB_INTR_TRANSFER, +#if USB_HAVE_TT_SUPPORT + UHUB_RESET_TT_TRANSFER, +#endif + UHUB_N_TRANSFER, +}; + + +struct uhub_current_state { + uint16_t port_change; + uint16_t port_status; +}; + +struct uhub_softc { + struct uhub_current_state sc_st;/* current state */ +#if (USB_HAVE_FIXED_PORT != 0) + struct usb_hub sc_hub; +#endif + device_t sc_dev; /* base device */ + struct mtx sc_mtx; /* our mutex */ + struct usb_device *sc_udev; /* USB device */ + struct usb_xfer *sc_xfer[UHUB_N_TRANSFER]; /* interrupt xfer */ +#if USB_HAVE_DISABLE_ENUM + int sc_disable_enumeration; + int sc_disable_port_power; +#endif + uint8_t sc_usb_port_errors; /* error counter */ +#define UHUB_USB_PORT_ERRORS_MAX 4 + uint8_t sc_flags; +#define UHUB_FLAG_DID_EXPLORE 0x01 +}; +struct hub_result { + struct usb_device *udev; + uint8_t portno; + uint8_t iface_index; +}; + +void uhub_find_iface_index(struct usb_hub *hub, device_t child, + struct hub_result *res); + +device_probe_t uhub_probe; +device_attach_t uhub_attach; +device_detach_t uhub_detach; +bus_child_location_str_t uhub_child_location_string; + +#endif Index: sys/modules/usb/usb/Makefile =================================================================== --- sys/modules/usb/usb/Makefile +++ sys/modules/usb/usb/Makefile @@ -39,6 +39,8 @@ usb_msctest.c usb_parse.c usb_pf.c usb_process.c usb_request.c \ usb_transfer.c usb_util.c +SRCS += opt_acpi.h usb_hub_acpi.c acpi_if.h + .if !empty(OPT_FDT) SRCS+= usb_fdt_support.c ofw_bus_if.h .endif