diff options
Diffstat (limited to 'src/barebox-state/state.c')
-rw-r--r-- | src/barebox-state/state.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/barebox-state/state.c b/src/barebox-state/state.c index e907290..804ac6c 100644 --- a/src/barebox-state/state.c +++ b/src/barebox-state/state.c @@ -33,6 +33,167 @@ /* list of all registered state instances */ static LIST_HEAD(state_list); +/** + * Save the state + * @param state + * @return + */ +int state_save(struct state *state) +{ + uint8_t *buf; + ssize_t len; + int ret; + + if (!state->dirty) + return 0; + + ret = state->format->pack(state->format, state, &buf, &len); + if (ret) { + dev_err(&state->dev, "Failed to pack state with backend format %s, %d\n", + state->format->name, ret); + return ret; + } + + ret = state_storage_write(&state->storage, buf, len); + if (ret) { + dev_err(&state->dev, "Failed to write packed state, %d\n", ret); + goto out; + } + + state->dirty = 0; + +out: + free(buf); + return ret; +} + +/** + * state_load - Loads a state from the backend + * @param state The state that should be updated to contain the loaded data + * @return 0 on success, -errno on failure. If no state is loaded the previous + * values remain in the state. + * + * This function uses the registered storage backend to read data. All data that + * we read is checked for integrity by the formatter. After that we unpack the + * data into our state. + */ +int state_load(struct state *state) +{ + uint8_t *buf; + ssize_t len; + int ret; + + ret = state_storage_read(&state->storage, state->format, + state->magic, &buf, &len); + if (ret) { + dev_err(&state->dev, "Failed to read state with format %s, %d\n", + state->format->name, ret); + return ret; + } + + ret = state->format->unpack(state->format, state, buf, len); + if (ret) { + dev_err(&state->dev, "Failed to unpack read data with format %s although verified, %d\n", + state->format->name, ret); + goto out; + } + + state->dirty = 0; + +out: + free(buf); + return ret; +} + +static int state_format_init(struct state *state, + struct device_d *dev, const char *backend_format, + struct device_node *node, const char *state_name) +{ + int ret; + + if (!backend_format || !strcmp(backend_format, "raw")) { + ret = backend_format_raw_create(&state->format, node, + state_name, dev); + } else if (!strcmp(backend_format, "dtb")) { + ret = backend_format_dtb_create(&state->format, dev); + } else { + dev_err(dev, "Invalid backend format %s\n", + backend_format); + return -EINVAL; + } + + if (ret && ret != -EPROBE_DEFER) + dev_err(dev, "Failed to initialize format %s, %d\n", + backend_format, ret); + + return ret; +} + +static void state_format_free(struct state_backend_format *format) +{ + if (format->free) + format->free(format); +} + +/** + * state_backend_init - Initiates the backend storage and format using the + * passed arguments + * @param backend state backend + * @param dev Device pointer used for prints + * @param node the DT device node corresponding to the state + * @param backend_format a string describing the format. Valid values are 'raw' + * and 'dtb' currently + * @param storage_path Path to the backend storage file/device/partition/... + * @param state_name Name of the state + * @param of_path Path in the devicetree + * @param stridesize stridesize in case we have a medium without eraseblocks. + * stridesize describes how far apart copies of the same data should be stored. + * For blockdevices it makes sense to align them on blocksize. + * @param storagetype Type of the storage backend. This may be NULL where we + * autoselect some backwardscompatible backend options + * @return 0 on success, -errno otherwise + */ +static int state_backend_init(struct state *state, struct device_d *dev, + struct device_node *node, const char *backend_format, + const char *storage_path, const char *state_name, const + char *of_path, off_t offset, size_t max_size, + uint32_t stridesize, const char *storagetype) +{ + int ret; + + ret = state_format_init(state, dev, backend_format, node, state_name); + if (ret) + return ret; + + ret = state_storage_init(&state->storage, dev, storage_path, offset, + max_size, stridesize, storagetype); + if (ret) + goto out_free_format; + + state->of_backend_path = xstrdup(of_path); + + return 0; + +out_free_format: + state_format_free(state->format); + state->format = NULL; + + return ret; +} + +void state_backend_set_readonly(struct state *state) +{ + state_storage_set_readonly(&state->storage); +} + +void state_backend_free(struct state *state) +{ + state_storage_free(&state->storage); + if (state->format) + state_format_free(state->format); + free(state->of_path); +} + static struct state *state_new(const char *name) { struct state *state; |