* [PATCH V3 3/8] usb: Bind devices to ACPI devices when possible
2012-05-09 15:00 [PATCH V3 0/8] usb/acpi: Add binding usb device with acpi Lan Tianyu
2012-05-09 15:00 ` [PATCH V3 1/8] ACPI: Add stubs for (un)register_acpi_bus_type Lan Tianyu
@ 2012-05-09 15:00 ` Lan Tianyu
2012-05-10 23:01 ` Greg KH
[not found] ` <1336575635-13120-1-git-send-email-tianyu.lan-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
` (3 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Lan Tianyu @ 2012-05-09 15:00 UTC (permalink / raw)
To: lenb, gregkh
Cc: linux-usb, linux-acpi, stern, sarah.a.sharp, mjg59, mfm,
Matthew Garrett, Lan Tianyu
From: Matthew Garrett <mjg@redhat.com>
Built-in USB devices will typically have a representation in the system
ACPI tables. Add support for binding the two together so the USB code can
make use of the associated methods.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
---
drivers/usb/core/Makefile | 1 +
drivers/usb/core/usb-acpi.c | 60 +++++++++++++++++++++++++++++++++++++++++++
drivers/usb/core/usb.c | 6 ++++
drivers/usb/core/usb.h | 7 +++++
4 files changed, 74 insertions(+), 0 deletions(-)
create mode 100644 drivers/usb/core/usb-acpi.c
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 507a4e1..9268ddb 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -10,5 +10,6 @@ usbcore-y += devio.o notify.o generic.o quirks.o devices.o
usbcore-$(CONFIG_PCI) += hcd-pci.o
usbcore-$(CONFIG_USB_DEVICEFS) += inode.o
+usbcore-$(CONFIG_ACPI) += usb-acpi.o
obj-$(CONFIG_USB) += usbcore.o
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
new file mode 100644
index 0000000..cab5cb7
--- /dev/null
+++ b/drivers/usb/core/usb-acpi.c
@@ -0,0 +1,60 @@
+/*
+ * USB-ACPI glue code
+ *
+ * Copyright 2012 Red Hat <mjg@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <acpi/acpi_bus.h>
+
+#include "usb.h"
+
+static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct usb_device *udev;
+ struct device *parent;
+ acpi_handle *parent_handle;
+
+ if (!is_usb_device(dev))
+ return -ENODEV;
+
+ udev = to_usb_device(dev);
+ parent = dev->parent;
+ parent_handle = DEVICE_ACPI_HANDLE(parent);
+
+ if (!parent_handle)
+ return -ENODEV;
+
+ *handle = acpi_get_child(parent_handle, udev->portnum);
+
+ if (!*handle)
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct acpi_bus_type usb_acpi_bus = {
+ .bus = &usb_bus_type,
+ .find_bridge = NULL,
+ .find_device = usb_acpi_find_device,
+};
+
+int usb_acpi_register(void)
+{
+ return register_acpi_bus_type(&usb_acpi_bus);
+}
+
+void usb_acpi_unregister(void)
+{
+ unregister_acpi_bus_type(&usb_acpi_bus);
+}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index c74ba7b..84e8c20 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1015,6 +1015,9 @@ static int __init usb_init(void)
if (retval)
goto out;
+ retval = usb_acpi_register();
+ if (retval)
+ goto acpi_register_failed;
retval = bus_register(&usb_bus_type);
if (retval)
goto bus_register_failed;
@@ -1054,6 +1057,8 @@ major_init_failed:
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
+ usb_acpi_unregister();
+acpi_register_failed:
usb_debugfs_cleanup();
out:
return retval;
@@ -1076,6 +1081,7 @@ static void __exit usb_exit(void)
usb_hub_cleanup();
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_unregister(&usb_bus_type);
+ usb_acpi_unregister();
usb_debugfs_cleanup();
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 71648dc..5c5c538 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -156,3 +156,10 @@ extern void usb_notify_remove_device(struct usb_device *udev);
extern void usb_notify_add_bus(struct usb_bus *ubus);
extern void usb_notify_remove_bus(struct usb_bus *ubus);
+#ifdef CONFIG_ACPI
+extern int usb_acpi_register(void);
+extern void usb_acpi_unregister(void);
+#else
+static inline int usb_acpi_register(void) { return 0; };
+static inline void usb_acpi_unregister(void) { };
+#endif
--
1.7.6.rc2.8.g28eb
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH V3 5/8] usb: add struct usb_hub_port to store port related members.
2012-05-09 15:00 [PATCH V3 0/8] usb/acpi: Add binding usb device with acpi Lan Tianyu
` (2 preceding siblings ...)
[not found] ` <1336575635-13120-1-git-send-email-tianyu.lan-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
@ 2012-05-09 15:00 ` Lan Tianyu
2012-05-09 15:00 ` [PATCH V3 6/8] usb: move struct usb_device->children to struct usb_hub_port->child Lan Tianyu
2012-05-09 15:00 ` [PATCH V3 7/8] usb/acpi: add the support of usb hub ports' acpi binding without attached devices Lan Tianyu
5 siblings, 0 replies; 11+ messages in thread
From: Lan Tianyu @ 2012-05-09 15:00 UTC (permalink / raw)
To: lenb, gregkh
Cc: linux-usb, linux-acpi, stern, sarah.a.sharp, mjg59, mfm,
Lan Tianyu
Add struct usb_hub_port pointer port_data in the struct usb_hub and allocate
struct usb_hub_port perspectively for each ports to store private data.
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
---
drivers/usb/core/hub.c | 29 ++++++++++++++++-------------
1 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ec6c97d..0c17d5a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -37,6 +37,10 @@
#endif
#endif
+struct usb_hub_port {
+ void *port_owner;
+};
+
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
@@ -81,7 +85,7 @@ struct usb_hub {
u8 indicator[USB_MAXCHILDREN];
struct delayed_work leds;
struct delayed_work init_work;
- void **port_owners;
+ struct usb_hub_port *port_data;
};
static inline int hub_is_superspeed(struct usb_device *hdev)
@@ -1049,8 +1053,9 @@ static int hub_configure(struct usb_hub *hub,
hdev->children = kzalloc(hdev->maxchild *
sizeof(struct usb_device *), GFP_KERNEL);
- hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
- if (!hdev->children || !hub->port_owners) {
+ hub->port_data = kzalloc(hdev->maxchild * sizeof(struct usb_hub_port),
+ GFP_KERNEL);
+ if (!hub->port_data || !hdev->children) {
ret = -ENOMEM;
goto fail;
}
@@ -1305,7 +1310,7 @@ static void hub_disconnect(struct usb_interface *intf)
usb_free_urb(hub->urb);
kfree(hdev->children);
- kfree(hub->port_owners);
+ kfree(hub->port_data);
kfree(hub->descriptor);
kfree(hub->status);
kfree(hub->buffer);
@@ -1437,7 +1442,7 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,
/* This assumes that devices not managed by the hub driver
* will always have maxchild equal to 0.
*/
- *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
+ *ppowner = &(hdev_to_hub(hdev)->port_data[port1 - 1].port_owner);
return 0;
}
@@ -1472,16 +1477,14 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
{
+ struct usb_hub *hub = hdev_to_hub(hdev);
int n;
- void **powner;
- n = find_port_owner(hdev, 1, &powner);
- if (n == 0) {
- for (; n < hdev->maxchild; (++n, ++powner)) {
- if (*powner == owner)
- *powner = NULL;
- }
+ for (n = 0; n < hdev->maxchild; n++) {
+ if (hub->port_data[n].port_owner == owner)
+ hub->port_data[n].port_owner = NULL;
}
+
}
/* The caller must hold udev's lock */
@@ -1492,7 +1495,7 @@ bool usb_device_is_owned(struct usb_device *udev)
if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
return false;
hub = hdev_to_hub(udev->parent);
- return !!hub->port_owners[udev->portnum - 1];
+ return !!hub->port_data[udev->portnum - 1].port_owner;
}
--
1.7.6.rc2.8.g28eb
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH V3 6/8] usb: move struct usb_device->children to struct usb_hub_port->child
2012-05-09 15:00 [PATCH V3 0/8] usb/acpi: Add binding usb device with acpi Lan Tianyu
` (3 preceding siblings ...)
2012-05-09 15:00 ` [PATCH V3 5/8] usb: add struct usb_hub_port to store port related members Lan Tianyu
@ 2012-05-09 15:00 ` Lan Tianyu
2012-05-09 15:00 ` [PATCH V3 7/8] usb/acpi: add the support of usb hub ports' acpi binding without attached devices Lan Tianyu
5 siblings, 0 replies; 11+ messages in thread
From: Lan Tianyu @ 2012-05-09 15:00 UTC (permalink / raw)
To: lenb, gregkh
Cc: linux-usb, linux-acpi, stern, sarah.a.sharp, mjg59, mfm,
Lan Tianyu
Move child's pointer to the struct usb_hub_port since the child device
is directly associated with the port. Provide usb_get_hub_child_device()
to get child's pointer.
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
---
drivers/staging/usbip/usbip_common.c | 3 +-
drivers/usb/core/devices.c | 3 +-
drivers/usb/core/hub.c | 67 ++++++++++++++++++++--------------
drivers/usb/host/r8a66597-hcd.c | 3 +-
include/linux/usb.h | 4 +-
5 files changed, 47 insertions(+), 33 deletions(-)
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 70f23026..95beb76 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -157,8 +157,7 @@ static void usbip_dump_usb_device(struct usb_device *udev)
dev_dbg(dev, "have_langid %d, string_langid %d\n",
udev->have_langid, udev->string_langid);
- dev_dbg(dev, "maxchild %d, children %p\n",
- udev->maxchild, udev->children);
+ dev_dbg(dev, "maxchild %d\n", udev->maxchild);
}
static void usbip_dump_request_type(__u8 rt)
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index d956965..a83962b 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -590,7 +590,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
- struct usb_device *childdev = usbdev->children[chix];
+ struct usb_device *childdev =
+ usb_get_hub_child_device(usbdev, chix + 1);
if (childdev) {
usb_lock_device(childdev);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0c17d5a..6bf7124 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -39,6 +39,7 @@
struct usb_hub_port {
void *port_owner;
+ struct usb_device *child;
};
struct usb_hub {
@@ -93,7 +94,7 @@ static inline int hub_is_superspeed(struct usb_device *hdev)
return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
}
-/* Protect struct usb_device->state and ->children members
+/* Protect struct usb_device->state and struct usb_hub_port->child members
* Note: Both are also protected by ->dev.sem, except that ->state can
* change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
static DEFINE_SPINLOCK(device_state_lock);
@@ -176,7 +177,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus)
/* Note that hdev or one of its children must be locked! */
static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
{
- if (!hdev || !hdev->actconfig)
+ if (!hdev || !hdev->actconfig || !hdev->maxchild)
return NULL;
return usb_get_intfdata(hdev->actconfig->interface[0]);
}
@@ -649,8 +650,8 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
struct usb_device *hdev = hub->hdev;
int ret = 0;
- if (hdev->children[port1-1] && set_state)
- usb_set_device_state(hdev->children[port1-1],
+ if (hub->port_data[port1-1].child && set_state)
+ usb_set_device_state(hub->port_data[port1-1].child,
USB_STATE_NOTATTACHED);
if (!hub->error && !hub_is_superspeed(hub->hdev))
ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
@@ -806,7 +807,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
* which ports need attention.
*/
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
- struct usb_device *udev = hdev->children[port1-1];
+ struct usb_device *udev = hub->port_data[port1-1].child;
u16 portstatus, portchange;
portstatus = portchange = 0;
@@ -971,8 +972,8 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
if (type != HUB_SUSPEND) {
/* Disconnect all the children */
for (i = 0; i < hdev->maxchild; ++i) {
- if (hdev->children[i])
- usb_disconnect(&hdev->children[i]);
+ if (hub->port_data[i].child)
+ usb_disconnect(&hub->port_data[i].child);
}
}
@@ -1051,11 +1052,9 @@ static int hub_configure(struct usb_hub *hub,
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
(hdev->maxchild == 1) ? "" : "s");
- hdev->children = kzalloc(hdev->maxchild *
- sizeof(struct usb_device *), GFP_KERNEL);
hub->port_data = kzalloc(hdev->maxchild * sizeof(struct usb_hub_port),
GFP_KERNEL);
- if (!hub->port_data || !hdev->children) {
+ if (!hub->port_data) {
ret = -ENOMEM;
goto fail;
}
@@ -1287,7 +1286,6 @@ static unsigned highspeed_hubs;
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
- struct usb_device *hdev = interface_to_usbdev(intf);
/* Take the hub off the event list and don't let it be added again */
spin_lock_irq(&hub_event_lock);
@@ -1309,7 +1307,6 @@ static void hub_disconnect(struct usb_interface *intf)
highspeed_hubs--;
usb_free_urb(hub->urb);
- kfree(hdev->children);
kfree(hub->port_data);
kfree(hub->descriptor);
kfree(hub->status);
@@ -1397,6 +1394,7 @@ static int
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
{
struct usb_device *hdev = interface_to_usbdev (intf);
+ struct usb_hub *hub = usb_get_intfdata(intf);
/* assert ifno == 0 (part of hub spec) */
switch (code) {
@@ -1410,11 +1408,11 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
else {
info->nports = hdev->maxchild;
for (i = 0; i < info->nports; i++) {
- if (hdev->children[i] == NULL)
+ if (hub->port_data[i].child == NULL)
info->port[i] = 0;
else
info->port[i] =
- hdev->children[i]->devnum;
+ hub->port_data[i].child->devnum;
}
}
spin_unlock_irq(&device_state_lock);
@@ -1501,11 +1499,13 @@ bool usb_device_is_owned(struct usb_device *udev)
static void recursively_mark_NOTATTACHED(struct usb_device *udev)
{
+ struct usb_hub *hub = hdev_to_hub(udev);
int i;
for (i = 0; i < udev->maxchild; ++i) {
- if (udev->children[i])
- recursively_mark_NOTATTACHED(udev->children[i]);
+ if (hub->port_data[i].child)
+ recursively_mark_NOTATTACHED(
+ hub->port_data[i].child);
}
if (udev->state == USB_STATE_SUSPENDED)
udev->active_duration -= jiffies;
@@ -1669,6 +1669,7 @@ static void hub_free_dev(struct usb_device *udev)
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *udev = *pdev;
+ struct usb_hub *hub = hdev_to_hub(udev);
int i;
/* mark the device as inactive, so any further urb submissions for
@@ -1683,8 +1684,8 @@ void usb_disconnect(struct usb_device **pdev)
/* Free up all the children before we remove this device */
for (i = 0; i < udev->maxchild; i++) {
- if (udev->children[i])
- usb_disconnect(&udev->children[i]);
+ if (hub->port_data[i].child)
+ usb_disconnect(&hub->port_data[i].child);
}
/* deallocate hcd/hardware state ... nuking all pending urbs and
@@ -2765,7 +2766,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev;
- udev = hdev->children [port1-1];
+ udev = hub->port_data[port1-1].child;
if (udev && udev->can_submit) {
dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
if (PMSG_IS_AUTO(msg))
@@ -3266,7 +3267,7 @@ hub_power_remaining (struct usb_hub *hub)
remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
- struct usb_device *udev = hdev->children[port1 - 1];
+ struct usb_device *udev = hub->port_data[port1 - 1].child;
int delta;
if (!udev)
@@ -3330,7 +3331,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
#endif
/* Try to resuscitate an existing device */
- udev = hdev->children[port1-1];
+ udev = hub->port_data[port1-1].child;
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
udev->state != USB_STATE_NOTATTACHED) {
usb_lock_device(udev);
@@ -3359,7 +3360,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* Disconnect any existing devices under this port */
if (udev)
- usb_disconnect(&hdev->children[port1-1]);
+ usb_disconnect(&hub->port_data[port1-1].child);
clear_bit(port1, hub->change_bits);
/* We can forget about a "removed" device when there's a physical
@@ -3474,7 +3475,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
&& highspeed_hubs != 0)
check_highspeed (hub, udev, port1);
- /* Store the parent's children[] pointer. At this point
+ /* Store the hub port's child pointer. At this point
* udev becomes globally accessible, although presumably
* no one will look at it until hdev is unlocked.
*/
@@ -3488,7 +3489,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if (hdev->state == USB_STATE_NOTATTACHED)
status = -ENOTCONN;
else
- hdev->children[port1-1] = udev;
+ hub->port_data[port1-1].child = udev;
spin_unlock_irq(&device_state_lock);
/* Run it through the hoops (find a driver, etc) */
@@ -3496,7 +3497,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
status = usb_new_device(udev);
if (status) {
spin_lock_irq(&device_state_lock);
- hdev->children[port1-1] = NULL;
+ hub->port_data[port1-1].child = NULL;
spin_unlock_irq(&device_state_lock);
}
}
@@ -3542,7 +3543,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
int ret;
hdev = hub->hdev;
- udev = hdev->children[port-1];
+ udev = hub->port_data[port - 1].child;
if (!hub_is_superspeed(hdev)) {
if (!(portchange & USB_PORT_STAT_C_SUSPEND))
return 0;
@@ -3696,7 +3697,7 @@ static void hub_events(void)
*/
if (!(portstatus & USB_PORT_STAT_ENABLE)
&& !connect_change
- && hdev->children[i-1]) {
+ && hub->port_data[i-1].child) {
dev_err (hub_dev,
"port %i "
"disabled by hub (EMI?), "
@@ -4234,3 +4235,15 @@ void usb_queue_reset_device(struct usb_interface *iface)
schedule_work(&iface->reset_ws);
}
EXPORT_SYMBOL_GPL(usb_queue_reset_device);
+
+struct usb_device *usb_get_hub_child_device(struct usb_device *hdev,
+ int port1)
+{
+ struct usb_hub *hub = hdev_to_hub(hdev);
+
+ if (!hub || port1 > hdev->maxchild || port1 < 1)
+ return NULL;
+ return hub->port_data[port1 - 1].child;
+}
+EXPORT_SYMBOL_GPL(usb_get_hub_child_device);
+
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 2bf1320..8f4ec9f 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2040,7 +2040,8 @@ static void collect_usb_address_map(struct usb_device *udev, unsigned long *map)
map[udev->devnum/32] |= (1 << (udev->devnum % 32));
for (chix = 0; chix < udev->maxchild; chix++) {
- struct usb_device *childdev = udev->children[chix];
+ struct usb_device *childdev =
+ usb_get_hub_child_device(udev, chix + 1);
if (childdev)
collect_usb_address_map(childdev, map);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 73b68d1..5e7058d 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -428,7 +428,6 @@ enum usb_device_removable {
* access from userspace
* @usbfs_dentry: usbfs dentry entry for the device
* @maxchild: number of ports if hub
- * @children: child devices - USB devices that are attached to this hub
* @quirks: quirks of the whole device
* @urbnum: number of URBs submitted for the whole device
* @active_duration: total time device is not suspended
@@ -501,7 +500,6 @@ struct usb_device {
#endif
int maxchild;
- struct usb_device **children;
u32 quirks;
atomic_t urbnum;
@@ -527,6 +525,8 @@ static inline struct usb_device *interface_to_usbdev(struct usb_interface *intf)
extern struct usb_device *usb_get_dev(struct usb_device *dev);
extern void usb_put_dev(struct usb_device *dev);
+extern struct usb_device *usb_get_hub_child_device(struct usb_device *hdev,
+ int port1);
/* USB device locking */
#define usb_lock_device(udev) device_lock(&(udev)->dev)
--
1.7.6.rc2.8.g28eb
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH V3 7/8] usb/acpi: add the support of usb hub ports' acpi binding without attached devices.
2012-05-09 15:00 [PATCH V3 0/8] usb/acpi: Add binding usb device with acpi Lan Tianyu
` (4 preceding siblings ...)
2012-05-09 15:00 ` [PATCH V3 6/8] usb: move struct usb_device->children to struct usb_hub_port->child Lan Tianyu
@ 2012-05-09 15:00 ` Lan Tianyu
5 siblings, 0 replies; 11+ messages in thread
From: Lan Tianyu @ 2012-05-09 15:00 UTC (permalink / raw)
To: lenb, gregkh
Cc: linux-usb, linux-acpi, stern, sarah.a.sharp, mjg59, mfm,
Lan Tianyu
The usb port is a device in the acpi table but it's not in the linux
usb subsystem. USB hub port doesn't have struct device. So the acpi
glue framework only can cover the usb port connected with usb device
and store the acpi handle to struct device.archdata.acpi_handle. This
patch adds the member platform_data in the struct usb_hub_port and
gets the hub port's acpi_handle and store it in the port's platform_data
to resolve no attached device no binding problem. The acpi method "_UPC"
and "_PLD" can be accessed without attached device.
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
---
drivers/usb/core/hub.c | 20 ++++++++++++++++++++
drivers/usb/core/usb-acpi.c | 37 ++++++++++++++++++++++++++++++++++++-
drivers/usb/core/usb.h | 6 ++++++
3 files changed, 62 insertions(+), 1 deletions(-)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6bf7124..338f01b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -40,6 +40,7 @@
struct usb_hub_port {
void *port_owner;
struct usb_device *child;
+ unsigned long platform_data;
};
struct usb_hub {
@@ -1263,6 +1264,7 @@ static int hub_configure(struct usb_hub *hub,
if (hub->has_indicators && blinkenlights)
hub->indicator [0] = INDICATOR_CYCLE;
+ usb_acpi_bind_hub_ports(hdev);
hub_activate(hub, HUB_INIT);
return 0;
@@ -4247,3 +4249,21 @@ struct usb_device *usb_get_hub_child_device(struct usb_device *hdev,
}
EXPORT_SYMBOL_GPL(usb_get_hub_child_device);
+void usb_set_hub_port_platform_data(struct usb_device *hdev, int port1,
+ unsigned long data)
+{
+ struct usb_hub *hub = hdev_to_hub(hdev);
+
+ if (!hub || port1 > hdev->maxchild || port1 < 1)
+ return;
+ hub->port_data[port1 - 1].platform_data = data;
+}
+
+unsigned long usb_get_hub_port_platform_data(struct usb_device *hdev, int port1)
+{
+ struct usb_hub *hub = hdev_to_hub(hdev);
+
+ if (!hub || port1 > hdev->maxchild || port1 < 1)
+ return 0;
+ return hub->port_data[port1 - 1].platform_data;
+}
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 8947b20..004f3d7 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -83,7 +83,16 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
if (!parent_handle)
return -ENODEV;
- *handle = acpi_get_child(parent_handle, udev->portnum);
+ /**
+ * The root hub's acpi handle is got from acpi method.
+ * Other device's acpi handle can be got from the usb hub
+ * port's platform_data.
+ */
+ if (!udev->parent)
+ *handle = acpi_get_child(parent_handle, udev->portnum);
+ else
+ *handle = (acpi_handle)usb_get_hub_port_platform_data(
+ udev->parent, udev->portnum);
if (!*handle)
return -ENODEV;
@@ -106,6 +115,32 @@ static struct acpi_bus_type usb_acpi_bus = {
.find_device = usb_acpi_find_device,
};
+int usb_acpi_bind_hub_ports(struct usb_device *hdev)
+{
+ acpi_handle hub_handle = NULL;
+ acpi_handle port_handle = NULL;
+ struct device *dev = &hdev->dev;
+ int i;
+
+ hub_handle = DEVICE_ACPI_HANDLE(dev);
+ if (!hub_handle)
+ return -ENODEV;
+
+ /**
+ * The usb hub port is not a device in the usb subsystem but it is a device
+ * in the acpi table. Store its acpi handle in the platform data of usb
+ * hub port.
+ */
+ for (i = 1; i <= hdev->maxchild; i++) {
+ port_handle = acpi_get_child(hub_handle, i);
+ if (!port_handle)
+ continue;
+ usb_set_hub_port_platform_data(hdev, i,
+ (unsigned long)port_handle);
+ }
+ return 0;
+}
+
int usb_acpi_register(void)
{
return register_acpi_bus_type(&usb_acpi_bus);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 5c5c538..d69d5f6 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -155,11 +155,17 @@ extern void usb_notify_add_device(struct usb_device *udev);
extern void usb_notify_remove_device(struct usb_device *udev);
extern void usb_notify_add_bus(struct usb_bus *ubus);
extern void usb_notify_remove_bus(struct usb_bus *ubus);
+extern unsigned long usb_get_hub_port_platform_data(struct usb_device *hdev,
+ int port1);
+extern void usb_set_hub_port_platform_data(struct usb_device *hdev,
+ int port1, unsigned long data);
#ifdef CONFIG_ACPI
extern int usb_acpi_register(void);
extern void usb_acpi_unregister(void);
+extern int usb_acpi_bind_hub_ports(struct usb_device *hdev);
#else
static inline int usb_acpi_register(void) { return 0; };
static inline void usb_acpi_unregister(void) { };
+static inline int usb_acpi_bind_hub_ports(struct usb_device *dev) { return 0; };
#endif
--
1.7.6.rc2.8.g28eb
^ permalink raw reply related [flat|nested] 11+ messages in thread