Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 31 Jul 2012 12:19:12 +0900
From:      Takanori Watanabe <takawata@init-main.com>
To:        freebsd-acpi@freebsd.org, freebsd-usb@freebsd.org
Subject:   USB ACPI namespace mapping.
Message-ID:  <201207310319.q6V3JC6a014526@sana.init-main.com>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201207310319.q6V3JC6a014526>