summaryrefslogtreecommitdiffhomepage
path: root/device.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-10-03 01:56:37 +0200
committerFelix Fietkau <nbd@openwrt.org>2011-10-03 01:56:37 +0200
commitf6b38cb7c9ad0e7feba7cb7d2a1678af5e032000 (patch)
treebdd8833e10c25ebfc7d017e12d505619aac3ff6a /device.c
parent39f5ec857a31fe65e14cdf9b75927297e78015bb (diff)
more changes for config reload handling
Diffstat (limited to 'device.c')
-rw-r--r--device.c76
1 files changed, 71 insertions, 5 deletions
diff --git a/device.c b/device.c
index 77594be..caadbc3 100644
--- a/device.c
+++ b/device.c
@@ -298,15 +298,81 @@ device_free_unused(struct device *dev)
__device_free_unused(dev);
}
+enum dev_change_type
+device_reload_config(struct device *dev, struct blob_attr *attr)
+{
+ struct blob_attr *tb[__DEV_ATTR_MAX], *tb1[__DEV_ATTR_MAX];
+
+ blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb,
+ blob_data(attr), blob_len(attr));
+ blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb1,
+ blob_data(dev->config), blob_len(dev->config));
+
+ if (!config_diff(tb, tb1, &device_attr_list, NULL))
+ return DEV_CONFIG_NO_CHANGE;
+
+ device_init_settings(dev, tb);
+ return DEV_CONFIG_APPLIED;
+}
+
+static enum dev_change_type
+device_check_config(struct device *dev, struct blob_attr *attr)
+{
+ if (dev->type->reload)
+ return dev->type->reload(dev, attr);
+
+ return device_reload_config(dev, attr);
+}
+
+static void
+device_replace(struct device *dev, struct device *odev)
+{
+ struct device_user *dep, *tmp;
+ bool present = odev->present;
+
+ if (present)
+ device_set_present(odev, false);
+
+ list_for_each_entry_safe(dep, tmp, &odev->users, list) {
+ list_move_tail(&dep->list, &dev->users);
+ dep->dev = dev;
+ }
+ device_free(odev);
+
+ if (present)
+ device_set_present(dev, true);
+}
+
struct device *
device_create(const char *name, const struct device_type *type,
struct blob_attr *config)
{
- struct device *dev;
+ struct device *odev = NULL, *dev;
+ enum dev_change_type change;
+
+ odev = device_get(name, false);
+ if (odev) {
+ change = device_check_config(odev, config);
+ switch (change) {
+ case DEV_CONFIG_APPLIED:
+ free(odev->config);
+ odev->config = config_memdup(config);
+ if (odev->present) {
+ device_set_present(odev, false);
+ device_set_present(odev, true);
+ }
+ /* fall through */
+ case DEV_CONFIG_NO_CHANGE:
+ return odev;
+ case DEV_CONFIG_RECREATE:
+ break;
+ }
+ }
- dev = device_get(name, false);
- if (dev)
- return dev;
+ dev = type->create(config);
+ dev->config = config_memdup(config);
+ if (odev)
+ device_replace(dev, odev);
- return type->create(config);
+ return dev;
}