aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/core.c168
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/power.h5
-rw-r--r--drivers/base/power/runtime.c85
-rw-r--r--drivers/base/power/sysfs.c66
5 files changed, 126 insertions, 200 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 0455aa78fa13..3599ab2506d2 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -24,6 +24,8 @@
24#include "base.h" 24#include "base.h"
25#include "power/power.h" 25#include "power/power.h"
26 26
27extern const char *kobject_actions[];
28
27int (*platform_notify)(struct device * dev) = NULL; 29int (*platform_notify)(struct device * dev) = NULL;
28int (*platform_notify_remove)(struct device * dev) = NULL; 30int (*platform_notify_remove)(struct device * dev) = NULL;
29 31
@@ -303,10 +305,25 @@ out:
303static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, 305static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
304 const char *buf, size_t count) 306 const char *buf, size_t count)
305{ 307{
306 if (memcmp(buf, "add", 3) != 0) 308 size_t len = count;
307 dev_err(dev, "uevent: unsupported action-string; this will " 309 enum kobject_action action;
308 "be ignored in a future kernel version"); 310
311 if (len && buf[len-1] == '\n')
312 len--;
313
314 for (action = 0; action < KOBJ_MAX; action++) {
315 if (strncmp(kobject_actions[action], buf, len) != 0)
316 continue;
317 if (kobject_actions[action][len] != '\0')
318 continue;
319 kobject_uevent(&dev->kobj, action);
320 goto out;
321 }
322
323 dev_err(dev, "uevent: unsupported action-string; this will "
324 "be ignored in a future kernel version\n");
309 kobject_uevent(&dev->kobj, KOBJ_ADD); 325 kobject_uevent(&dev->kobj, KOBJ_ADD);
326out:
310 return count; 327 return count;
311} 328}
312 329
@@ -643,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent)
643 return 0; 660 return 0;
644} 661}
645 662
663static int device_add_class_symlinks(struct device *dev)
664{
665 int error;
666
667 if (!dev->class)
668 return 0;
669 error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
670 "subsystem");
671 if (error)
672 goto out;
673 /*
674 * If this is not a "fake" compatible device, then create the
675 * symlink from the class to the device.
676 */
677 if (dev->kobj.parent != &dev->class->subsys.kobj) {
678 error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
679 dev->bus_id);
680 if (error)
681 goto out_subsys;
682 }
683 /* only bus-device parents get a "device"-link */
684 if (dev->parent && dev->parent->bus) {
685 error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
686 "device");
687 if (error)
688 goto out_busid;
689#ifdef CONFIG_SYSFS_DEPRECATED
690 {
691 char * class_name = make_class_name(dev->class->name,
692 &dev->kobj);
693 if (class_name)
694 error = sysfs_create_link(&dev->parent->kobj,
695 &dev->kobj, class_name);
696 kfree(class_name);
697 if (error)
698 goto out_device;
699 }
700#endif
701 }
702 return 0;
703
704#ifdef CONFIG_SYSFS_DEPRECATED
705out_device:
706 if (dev->parent)
707 sysfs_remove_link(&dev->kobj, "device");
708#endif
709out_busid:
710 if (dev->kobj.parent != &dev->class->subsys.kobj)
711 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
712out_subsys:
713 sysfs_remove_link(&dev->kobj, "subsystem");
714out:
715 return error;
716}
717
718static void device_remove_class_symlinks(struct device *dev)
719{
720 if (!dev->class)
721 return;
722 if (dev->parent) {
723#ifdef CONFIG_SYSFS_DEPRECATED
724 char *class_name;
725
726 class_name = make_class_name(dev->class->name, &dev->kobj);
727 if (class_name) {
728 sysfs_remove_link(&dev->parent->kobj, class_name);
729 kfree(class_name);
730 }
731#endif
732 sysfs_remove_link(&dev->kobj, "device");
733 }
734 if (dev->kobj.parent != &dev->class->subsys.kobj)
735 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
736 sysfs_remove_link(&dev->kobj, "subsystem");
737}
738
646/** 739/**
647 * device_add - add device to device hierarchy. 740 * device_add - add device to device hierarchy.
648 * @dev: device. 741 * @dev: device.
@@ -657,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent)
657int device_add(struct device *dev) 750int device_add(struct device *dev)
658{ 751{
659 struct device *parent = NULL; 752 struct device *parent = NULL;
660 char *class_name = NULL;
661 struct class_interface *class_intf; 753 struct class_interface *class_intf;
662 int error = -EINVAL; 754 int error = -EINVAL;
663 755
@@ -697,27 +789,9 @@ int device_add(struct device *dev)
697 goto ueventattrError; 789 goto ueventattrError;
698 } 790 }
699 791
700 if (dev->class) { 792 error = device_add_class_symlinks(dev);
701 sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, 793 if (error)
702 "subsystem"); 794 goto SymlinkError;
703 /* If this is not a "fake" compatible device, then create the
704 * symlink from the class to the device. */
705 if (dev->kobj.parent != &dev->class->subsys.kobj)
706 sysfs_create_link(&dev->class->subsys.kobj,
707 &dev->kobj, dev->bus_id);
708 if (parent) {
709 sysfs_create_link(&dev->kobj, &dev->parent->kobj,
710 "device");
711#ifdef CONFIG_SYSFS_DEPRECATED
712 class_name = make_class_name(dev->class->name,
713 &dev->kobj);
714 if (class_name)
715 sysfs_create_link(&dev->parent->kobj,
716 &dev->kobj, class_name);
717#endif
718 }
719 }
720
721 error = device_add_attrs(dev); 795 error = device_add_attrs(dev);
722 if (error) 796 if (error)
723 goto AttrsError; 797 goto AttrsError;
@@ -744,7 +818,6 @@ int device_add(struct device *dev)
744 up(&dev->class->sem); 818 up(&dev->class->sem);
745 } 819 }
746 Done: 820 Done:
747 kfree(class_name);
748 put_device(dev); 821 put_device(dev);
749 return error; 822 return error;
750 BusError: 823 BusError:
@@ -755,6 +828,8 @@ int device_add(struct device *dev)
755 BUS_NOTIFY_DEL_DEVICE, dev); 828 BUS_NOTIFY_DEL_DEVICE, dev);
756 device_remove_attrs(dev); 829 device_remove_attrs(dev);
757 AttrsError: 830 AttrsError:
831 device_remove_class_symlinks(dev);
832 SymlinkError:
758 if (MAJOR(dev->devt)) 833 if (MAJOR(dev->devt))
759 device_remove_file(dev, &devt_attr); 834 device_remove_file(dev, &devt_attr);
760 835
@@ -1139,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name)
1139{ 1214{
1140 char *old_class_name = NULL; 1215 char *old_class_name = NULL;
1141 char *new_class_name = NULL; 1216 char *new_class_name = NULL;
1142 char *old_symlink_name = NULL; 1217 char *old_device_name = NULL;
1143 int error; 1218 int error;
1144 1219
1145 dev = get_device(dev); 1220 dev = get_device(dev);
@@ -1153,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name)
1153 old_class_name = make_class_name(dev->class->name, &dev->kobj); 1228 old_class_name = make_class_name(dev->class->name, &dev->kobj);
1154#endif 1229#endif
1155 1230
1156 if (dev->class) { 1231 old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
1157 old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); 1232 if (!old_device_name) {
1158 if (!old_symlink_name) { 1233 error = -ENOMEM;
1159 error = -ENOMEM; 1234 goto out;
1160 goto out_free_old_class;
1161 }
1162 strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
1163 } 1235 }
1164 1236 strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
1165 strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); 1237 strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
1166 1238
1167 error = kobject_rename(&dev->kobj, new_name); 1239 error = kobject_rename(&dev->kobj, new_name);
1240 if (error) {
1241 strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
1242 goto out;
1243 }
1168 1244
1169#ifdef CONFIG_SYSFS_DEPRECATED 1245#ifdef CONFIG_SYSFS_DEPRECATED
1170 if (old_class_name) { 1246 if (old_class_name) {
1171 new_class_name = make_class_name(dev->class->name, &dev->kobj); 1247 new_class_name = make_class_name(dev->class->name, &dev->kobj);
1172 if (new_class_name) { 1248 if (new_class_name) {
1173 sysfs_create_link(&dev->parent->kobj, &dev->kobj, 1249 error = sysfs_create_link(&dev->parent->kobj,
1174 new_class_name); 1250 &dev->kobj, new_class_name);
1251 if (error)
1252 goto out;
1175 sysfs_remove_link(&dev->parent->kobj, old_class_name); 1253 sysfs_remove_link(&dev->parent->kobj, old_class_name);
1176 } 1254 }
1177 } 1255 }
1178#endif 1256#endif
1179 1257
1180 if (dev->class) { 1258 if (dev->class) {
1181 sysfs_remove_link(&dev->class->subsys.kobj, 1259 sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
1182 old_symlink_name); 1260 error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
1183 sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 1261 dev->bus_id);
1184 dev->bus_id); 1262 if (error) {
1263 /* Uh... how to unravel this if restoring can fail? */
1264 dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
1265 __FUNCTION__, error);
1266 }
1185 } 1267 }
1268out:
1186 put_device(dev); 1269 put_device(dev);
1187 1270
1188 kfree(new_class_name); 1271 kfree(new_class_name);
1189 kfree(old_symlink_name);
1190 out_free_old_class:
1191 kfree(old_class_name); 1272 kfree(old_class_name);
1273 kfree(old_device_name);
1192 1274
1193 return error; 1275 return error;
1194} 1276}
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 91f230939c1e..fff178007208 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
1obj-y := shutdown.o 1obj-y := shutdown.o
2obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o 2obj-$(CONFIG_PM) += main.o suspend.o resume.o sysfs.o
3obj-$(CONFIG_PM_TRACE) += trace.o 3obj-$(CONFIG_PM_TRACE) += trace.o
4 4
5ifeq ($(CONFIG_DEBUG_DRIVER),y) 5ifeq ($(CONFIG_DEBUG_DRIVER),y)
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 2760f25b3ac5..591a0dd5deee 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -62,11 +62,6 @@ extern int resume_device(struct device *);
62 */ 62 */
63extern int suspend_device(struct device *, pm_message_t); 63extern int suspend_device(struct device *, pm_message_t);
64 64
65
66/*
67 * runtime.c
68 */
69
70#else /* CONFIG_PM */ 65#else /* CONFIG_PM */
71 66
72 67
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
deleted file mode 100644
index df6174d85866..000000000000
--- a/drivers/base/power/runtime.c
+++ /dev/null
@@ -1,85 +0,0 @@
1/*
2 * drivers/base/power/runtime.c - Handling dynamic device power management.
3 *
4 * Copyright (c) 2003 Patrick Mochel
5 * Copyright (c) 2003 Open Source Development Lab
6 *
7 */
8
9#include <linux/device.h>
10#include "power.h"
11
12
13static void runtime_resume(struct device * dev)
14{
15 dev_dbg(dev, "resuming\n");
16 if (!dev->power.power_state.event)
17 return;
18 if (!resume_device(dev))
19 dev->power.power_state = PMSG_ON;
20}
21
22
23/**
24 * dpm_runtime_resume - Power one device back on.
25 * @dev: Device.
26 *
27 * Bring one device back to the on state by first powering it
28 * on, then restoring state. We only operate on devices that aren't
29 * already on.
30 * FIXME: We need to handle devices that are in an unknown state.
31 */
32
33void dpm_runtime_resume(struct device * dev)
34{
35 mutex_lock(&dpm_mtx);
36 runtime_resume(dev);
37 mutex_unlock(&dpm_mtx);
38}
39EXPORT_SYMBOL(dpm_runtime_resume);
40
41
42/**
43 * dpm_runtime_suspend - Put one device in low-power state.
44 * @dev: Device.
45 * @state: State to enter.
46 */
47
48int dpm_runtime_suspend(struct device * dev, pm_message_t state)
49{
50 int error = 0;
51
52 mutex_lock(&dpm_mtx);
53 if (dev->power.power_state.event == state.event)
54 goto Done;
55
56 if (dev->power.power_state.event)
57 runtime_resume(dev);
58
59 if (!(error = suspend_device(dev, state)))
60 dev->power.power_state = state;
61 Done:
62 mutex_unlock(&dpm_mtx);
63 return error;
64}
65EXPORT_SYMBOL(dpm_runtime_suspend);
66
67
68#if 0
69/**
70 * dpm_set_power_state - Update power_state field.
71 * @dev: Device.
72 * @state: Power state device is in.
73 *
74 * This is an update mechanism for drivers to notify the core
75 * what power state a device is in. Device probing code may not
76 * always be able to tell, but we need accurate information to
77 * work reliably.
78 */
79void dpm_set_power_state(struct device * dev, pm_message_t state)
80{
81 mutex_lock(&dpm_mtx);
82 dev->power.power_state = state;
83 mutex_unlock(&dpm_mtx);
84}
85#endif /* 0 */
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 2d47517dbe32..f2ed179cd695 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -7,69 +7,6 @@
7#include "power.h" 7#include "power.h"
8 8
9 9
10#ifdef CONFIG_PM_SYSFS_DEPRECATED
11
12/**
13 * state - Control current power state of device
14 *
15 * show() returns the current power state of the device. '0' indicates
16 * the device is on. Other values (2) indicate the device is in some low
17 * power state.
18 *
19 * store() sets the current power state, which is an integer valued
20 * 0, 2, or 3. Devices with bus.suspend_late(), or bus.resume_early()
21 * methods fail this operation; those methods couldn't be called.
22 * Otherwise,
23 *
24 * - If the recorded dev->power.power_state.event matches the
25 * target value, nothing is done.
26 * - If the recorded event code is nonzero, the device is reactivated
27 * by calling bus.resume() and/or class.resume().
28 * - If the target value is nonzero, the device is suspended by
29 * calling class.suspend() and/or bus.suspend() with event code
30 * PM_EVENT_SUSPEND.
31 *
32 * This mechanism is DEPRECATED and should only be used for testing.
33 */
34
35static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
36{
37 if (dev->power.power_state.event)
38 return sprintf(buf, "2\n");
39 else
40 return sprintf(buf, "0\n");
41}
42
43static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
44{
45 pm_message_t state;
46 int error = -EINVAL;
47
48 /* disallow incomplete suspend sequences */
49 if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
50 return error;
51
52 state.event = PM_EVENT_SUSPEND;
53 /* Older apps expected to write "3" here - confused with PCI D3 */
54 if ((n == 1) && !strcmp(buf, "3"))
55 error = dpm_runtime_suspend(dev, state);
56
57 if ((n == 1) && !strcmp(buf, "2"))
58 error = dpm_runtime_suspend(dev, state);
59
60 if ((n == 1) && !strcmp(buf, "0")) {
61 dpm_runtime_resume(dev);
62 error = 0;
63 }
64
65 return error ? error : n;
66}
67
68static DEVICE_ATTR(state, 0644, state_show, state_store);
69
70
71#endif /* CONFIG_PM_SYSFS_DEPRECATED */
72
73/* 10/*
74 * wakeup - Report/change current wakeup option for device 11 * wakeup - Report/change current wakeup option for device
75 * 12 *
@@ -143,9 +80,6 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
143 80
144 81
145static struct attribute * power_attrs[] = { 82static struct attribute * power_attrs[] = {
146#ifdef CONFIG_PM_SYSFS_DEPRECATED
147 &dev_attr_state.attr,
148#endif
149 &dev_attr_wakeup.attr, 83 &dev_attr_wakeup.attr,
150 NULL, 84 NULL,
151}; 85};