USB ACPI namespace mapping.
Takanori Watanabe
takawata at init-main.com
Tue Jul 31 03:19:57 UTC 2012
I'm trying to map USB devices and hub into acpi handle,
and I want ideas to cope with a problem.
The problem is that there is no easy way to get port number from
child usb device in hub device.
usb_attach_arg structure have one, but invalidate after probe and attach.
And, furthermore, which device_t instance should I register to acpi
device handle to cope with ACPI docking station framework.
The code I wrote is as follows.
Index: usb_hub.c
===================================================================
--- usb_hub.c (revision 238557)
+++ usb_hub.c (working copy)
@@ -69,10 +69,11 @@
#include <dev/usb/usb_controller.h>
#include <dev/usb/usb_bus.h>
+#include <dev/usb/usb_hub_private.h>
#define UHUB_INTR_INTERVAL 250 /* ms */
-#define UHUB_N_TRANSFER 1
+
#ifdef USB_DEBUG
static int uhub_debug = 0;
@@ -90,42 +91,15 @@
&usb_power_timeout, 0, "USB power timeout");
#endif
-struct uhub_current_state {
- uint16_t port_change;
- uint16_t port_status;
-};
-
-struct uhub_softc {
- struct uhub_current_state sc_st;/* current state */
- 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 */
- uint8_t sc_flags;
-#define UHUB_FLAG_DID_EXPLORE 0x01
- char sc_name[32];
-};
-
#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)
#define UHUB_IS_MULTI_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBMTT)
#define UHUB_IS_SUPER_SPEED(sc) (UHUB_PROTO(sc) == UDPROTO_SSHUB)
-/* 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;
+
static void usb_dev_resume_peer(struct usb_device *udev);
static void usb_dev_suspend_peer(struct usb_device *udev);
static uint8_t usb_peer_should_wakeup(struct usb_device *udev);
@@ -164,7 +138,7 @@
{0, 0}
};
-static driver_t uhub_driver = {
+driver_t uhub_driver = {
.name = "uhub",
.methods = uhub_methods,
.size = sizeof(struct uhub_softc)
@@ -821,8 +795,7 @@
return (USB_ERR_NORMAL_COMPLETION);
}
-static int
-uhub_probe(device_t dev)
+int uhub_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
@@ -835,7 +808,7 @@
*/
if (uaa->info.bConfigIndex == 0 &&
uaa->info.bDeviceClass == UDCLASS_HUB)
- return (0);
+ return (BUS_PROBE_GENERIC);
return (ENXIO);
}
@@ -900,8 +873,7 @@
return (err);
}
-
-static int
+int
uhub_attach(device_t dev)
{
struct uhub_softc *sc = device_get_softc(dev);
@@ -1204,7 +1176,8 @@
* 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);
@@ -1241,7 +1214,7 @@
return (0);
}
-static int
+int
uhub_suspend(device_t dev)
{
DPRINTF("\n");
@@ -1249,7 +1222,7 @@
return (0);
}
-static int
+int
uhub_resume(device_t dev)
{
DPRINTF("\n");
@@ -1257,7 +1230,7 @@
return (0);
}
-static void
+void
uhub_driver_added(device_t dev, driver_t *driver)
{
usb_needs_explore_all();
@@ -1302,7 +1275,7 @@
res->portno = 0;
}
-static int
+int
uhub_child_location_string(device_t parent, device_t child,
char *buf, size_t buflen)
{
@@ -1338,7 +1311,7 @@
return (0);
}
-static int
+int
uhub_child_pnpinfo_string(device_t parent, device_t child,
char *buf, size_t buflen)
{
Index: usb_hub_acpi.c
===================================================================
--- usb_hub_acpi.c (revision 0)
+++ usb_hub_acpi.c (revision 0)
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2012 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.
+ *
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_ioctl.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_device.h>
+#include <dev/usb/usb_request.h>
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_hub.h>
+#include <dev/usb/usb_util.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_transfer.h>
+#include <dev/usb/usb_dynamic.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+#include <dev/usb/usb_hub_private.h>
+
+
+#define MAX_PORT 32
+
+struct uhub_acpi_softc{
+ struct uhub_softc base; /*must be first member*/
+ ACPI_HANDLE hub_handle;
+ ACPI_HANDLE port_handle[MAX_PORT];
+};
+
+static int
+uhub_acpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct uhub_acpi_softc *sc = device_get_softc(dev);
+ struct usb_attach_arg *ivars = device_get_ivars(child);
+
+ switch (which) {
+ case ACPI_IVAR_HANDLE:
+#if 0 /*XXX*/
+ *result = (uintptr_t)sc->port_handle[ivars->port];
+#endif
+ return (0);
+ }
+ return ENXIO;
+}
+
+static ACPI_STATUS uhub_acpi_port_probe(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
+{
+ ACPI_DEVICE_INFO *devinfo;
+ device_t dev =(device_t)context;
+ struct uhub_acpi_softc *sc = device_get_softc(dev);
+
+
+ if(AcpiGetObjectInfo(handle, &devinfo))
+ return AE_OK;
+ if(!(devinfo->Valid&ACPI_VALID_ADR)){
+ return AE_OK;
+ }
+ if(devinfo->Address == 0){
+ device_printf(dev, "port 0 is root hub only\n");
+ return AE_OK;
+ }
+
+ if(devinfo->Address > MAX_PORT){
+ device_printf(dev, "Too high port in the hub %lld\n",
+ devinfo->Address);
+ return AE_OK;
+ }
+ device_printf(dev, "%s at port %lld\n", acpi_name(handle),
+ devinfo->Address);
+ sc->port_handle[devinfo->Address -1] = handle;
+
+ return AE_OK;
+}
+
+static ACPI_STATUS uhub_root_acpi_handle(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
+{
+ ACPI_DEVICE_INFO *devinfo;
+
+ *status = NULL;
+
+ if(AcpiGetObjectInfo(handle, &devinfo))
+ return AE_OK;
+ if(!(devinfo->Valid&ACPI_VALID_ADR)){
+ return AE_OK;
+ }
+ if(devinfo->Address != 0){
+ printf("Non zero Address for root hub %llx\n",
+ devinfo->Address);
+ return AE_OK;
+ }
+ *status = (void *)handle;
+ return AE_CTRL_TERMINATE;
+}
+
+static ACPI_HANDLE uhub_acpi_my_handle(device_t dev)
+{
+
+ ACPI_HANDLE h,childh;
+
+ if(strcmp(device_get_name(device_get_parent(dev)), "usbus") ==0){
+ h = acpi_get_handle(device_get_parent(device_get_parent(dev)));
+ AcpiWalkNamespace(ACPI_TYPE_DEVICE, h, 1,
+ uhub_root_acpi_handle,
+ NULL,dev, &childh);
+
+ }else{
+ childh = acpi_get_handle(dev);
+ }
+
+ return childh;
+}
+
+static int
+uhub_acpi_probe(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return (ENXIO);
+
+
+ if(uhub_acpi_my_handle(dev) == NULL){
+ return ENXIO;
+ }
+ device_printf(dev, "ACPI capable\n");
+ /*
+ * The subclass for USB HUBs is currently ignored because it
+ * is 0 for some and 1 for others.
+ */
+
+ if (uaa->info.bConfigIndex == 0 &&
+ uaa->info.bDeviceClass == UDCLASS_HUB){
+ return (0);
+ }
+
+ return (ENXIO);
+}
+static int uhub_acpi_attach(device_t dev)
+{
+ struct uhub_acpi_softc *sc = device_get_softc(dev);
+ sc->hub_handle = uhub_acpi_my_handle(dev);
+ device_printf(dev, "PATH:%s\n", acpi_name(sc->hub_handle));
+
+ AcpiWalkNamespace(ACPI_TYPE_DEVICE, sc->hub_handle, 1,
+ uhub_acpi_port_probe,
+ NULL,dev, NULL);
+
+
+ return uhub_attach(dev);
+}
+
+
+static int
+uhub_acpi_child_location_string(device_t parent, device_t child,
+ char *buf, size_t buflen)
+{
+
+ int len = 0;
+#if 0 /*XXX*/
+ struct uhub_acpi_softc *sc = device_get_softc(child);
+ struct usb_attach_arg *uaa = device_get_ivars(child);
+
+ len = snprintf(buf, buflen,
+ "handle=%s ", acpi_name(sc->port_handle[uaa->port]));
+#endif
+ return uhub_child_location_string(parent, child,
+ buf + len, buflen - len);
+}
+
+
+static device_method_t uhub_acpi_methods[] = {
+ DEVMETHOD(device_probe, uhub_acpi_probe),
+ DEVMETHOD(device_attach, uhub_acpi_attach),
+
+ DEVMETHOD(bus_read_ivar, uhub_acpi_read_ivar),
+ DEVMETHOD(bus_child_location_str, uhub_acpi_child_location_string),
+
+ {0, 0}
+};
+
+static devclass_t uhub_devclass;
+DECLARE_CLASS(uhub_driver);
+
+DEFINE_CLASS_1(uhub, uhub_acpi_driver, uhub_acpi_methods,
+ sizeof(struct uhub_acpi_softc),uhub_driver);
+
+DRIVER_MODULE(uhub_acpi, usbus, uhub_acpi_driver, uhub_devclass, 0, 0);
+DRIVER_MODULE(uhub_acpi, uhub, uhub_acpi_driver, uhub_devclass, NULL, 0);
Index: usb_hub_private.h
===================================================================
--- usb_hub_private.h (revision 0)
+++ usb_hub_private.h (revision 0)
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2012 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.
+ *
+ */
+
+#ifndef _USB_HUB_PRIVATE_H
+#define _USB_HUB_PRIVATE_H
+
+#define UHUB_N_TRANSFER 1
+struct uhub_current_state {
+ uint16_t port_change;
+ uint16_t port_status;
+};
+
+struct uhub_softc {
+ struct uhub_current_state sc_st;/* current state */
+ 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 */
+ uint8_t sc_flags;
+#define UHUB_FLAG_DID_EXPLORE 0x01
+ char sc_name[32];
+};
+
+
+device_probe_t uhub_probe;
+device_attach_t uhub_attach;
+device_detach_t uhub_detach;
+device_suspend_t uhub_suspend;
+device_resume_t uhub_resume;
+
+bus_driver_added_t uhub_driver_added;
+bus_child_location_str_t uhub_child_location_string;
+bus_child_pnpinfo_str_t uhub_child_pnpinfo_string;
+
+#endif
More information about the freebsd-acpi
mailing list