--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <hal/hal-device-board-interface.h>
+#include <hal/hal-common-interface.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include </hal/include/device/hal-backend-common.h>
+#include <libsyscommon/file.h>
+
+#define INFORM_MNT_PATH "/mnt/inform"
+#define PARTITION_AB_PATH INFORM_MNT_PATH"/partition-ab.info"
+#define PARTITION_AB_CLONED_PATH INFORM_MNT_PATH"/partition-ab-cloned.info"
+#define UPGRADE_PROGRESS_STATUS_PATH INFORM_MNT_PATH"/upgrade-progress-status.info"
+#define PARTITION_A_STATUS_PATH INFORM_MNT_PATH"/partition-a-status.info"
+#define PARTITION_B_STATUS_PATH INFORM_MNT_PATH"/partition-b-status.info"
+#define REBOOT_PARAM_PATH INFORM_MNT_PATH"/reboot-param.bin"
+#define UPGRADE_STATE_PATH INFORM_MNT_PATH"/upgrade-state.info"
+#define SERIAL_FILE_PATH "/sys/firmware/devicetree/base/serial-number"
+
+#define PARTITION_STATUS_OK "ok"
+#define PARTITION_STATUS_CORRUPTED "corrupted"
+#define PARTITION_STATUS_FAILED "failed"
+#define BOOT_MODE_NORMAL "norm"
+
+static int get_device_serial_number(char *buffer, int len)
+{
+ FILE *fp;
+ char *retval;
+
+ fp = fopen(SERIAL_FILE_PATH, "r");
+ if (!fp)
+ return -errno;
+
+ retval = fgets(buffer, len, fp);
+ if (retval == NULL) {
+ fclose(fp);
+ return -errno;
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+static int clear_boot_mode(void)
+{
+ /* clear contents of the file first */
+ if (truncate(REBOOT_PARAM_PATH, 0) == -1) {
+ int ferror = errno;
+ errno = 0;
+ return -ferror;
+ }
+
+ return sys_set_str(REBOOT_PARAM_PATH, BOOT_MODE_NORMAL);
+}
+
+static int get_boot_mode(char *buffer, const int max_len)
+{
+ char scan_format[32] = { 0, };
+ int ret = 0;
+
+ snprintf(scan_format, sizeof(scan_format), "bootmode=%%%ds", max_len - 1);
+
+ ret = syscommon_parse_cmdline_scanf(scan_format, buffer);
+
+ if (ret <= 0) {
+ return -ENOENT;
+ }
+
+ if (!strncmp(buffer, "ramdisk", max_len)) {
+ snprintf(buffer, max_len, "normal");
+ }
+
+ return 0;
+}
+
+
+static int get_current_partition(char *partition_ab)
+{
+ int ret_parse = syscommon_parse_cmdline_scanf("partition_ab=%c", partition_ab);
+
+ if (ret_parse <= 0) {
+ return -ENOENT;
+ }
+
+ return 0;
+
+}
+
+static int switch_partition(char partition_ab)
+{
+ char cur_partition_ab;
+ char next_partition_ab[2];
+
+ next_partition_ab[0] = partition_ab;
+ next_partition_ab[1] = '\0';
+
+ if (partition_ab == '\0') {
+ /* Toggle partition a/b */
+ int ret_cur_part = get_current_partition(&cur_partition_ab);
+
+ if (ret_cur_part < 0) {
+ return ret_cur_part;
+ }
+
+ if (cur_partition_ab == 'a') {
+ next_partition_ab[0] = 'b';
+ } else if(cur_partition_ab == 'b') {
+ next_partition_ab[0] = 'a';
+ } else {
+ return -ENOENT;
+ }
+ } else if(partition_ab != 'a' && partition_ab != 'b') {
+ return -EINVAL;
+ }
+
+ return sys_write_buf(PARTITION_AB_PATH, next_partition_ab);
+}
+
+static int set_partition_ab_cloned(void)
+{
+ return sys_write_buf(PARTITION_AB_CLONED_PATH, "1");
+}
+
+static int clear_partition_ab_cloned(void)
+{
+ return sys_write_buf(PARTITION_AB_CLONED_PATH, "0");
+}
+
+static int get_partition_ab_cloned(int *cloned)
+{
+ int ret_get_int = sys_get_int(PARTITION_AB_CLONED_PATH, cloned);
+
+ if (ret_get_int < 0) {
+ return ret_get_int;
+ }
+
+ return 0;
+}
+
+static int set_partition_status(char partition_ab, const char *status)
+{
+ char *path;
+ char target_partition_ab = partition_ab;
+
+ if (target_partition_ab == '\0') {
+ int ret_cur_part = get_current_partition(&target_partition_ab);
+
+ if (ret_cur_part < 0) {
+ return ret_cur_part;
+ }
+
+ if (target_partition_ab != 'a' && target_partition_ab != 'b') {
+ return -ENOENT;
+ }
+ }
+
+ if (target_partition_ab == 'a') {
+ path = PARTITION_A_STATUS_PATH;
+ } else if (target_partition_ab == 'b') {
+ path = PARTITION_B_STATUS_PATH;
+ } else {
+ return -EINVAL;
+ }
+
+ if (status == NULL || (strcmp(status, PARTITION_STATUS_OK) != 0 &&
+ strcmp(status, PARTITION_STATUS_CORRUPTED) != 0 &&
+ strcmp(status, PARTITION_STATUS_FAILED) != 0)) {
+ return -EINVAL;
+ }
+
+ /* clear contents of the file first */
+ if (truncate(path, 0) == -1) {
+ int ferror = errno;
+ errno = 0;
+ return -ferror;
+ }
+
+ return sys_set_str(path, (char *)status);
+}
+
+static int get_partition_status(char partition_ab, char *buffer, const int max_len)
+{
+ char *dummy;
+ char *path;
+ char target_partition_ab = partition_ab;
+
+ if (target_partition_ab == '\0') {
+ int ret_cur_part = get_current_partition(&target_partition_ab);
+
+ if (ret_cur_part < 0) {
+ return ret_cur_part;
+ }
+
+ if (target_partition_ab != 'a' && target_partition_ab != 'b') {
+ return -ENOENT;
+ }
+ }
+
+ if (target_partition_ab == 'a') {
+ path = PARTITION_A_STATUS_PATH;
+ } else if (target_partition_ab == 'b') {
+ path = PARTITION_B_STATUS_PATH;
+ } else {
+ return -EINVAL;
+ }
+
+ int res_get_str = sys_get_str(path, buffer, max_len);
+ if (res_get_str < 0) {
+ return res_get_str;
+ }
+
+ /* remove potential newline | tokenizer will place '\0' in a place of '\n' */
+ strtok_r(buffer, "\n", &dummy);
+
+ if (strcmp(buffer, PARTITION_STATUS_OK) != 0 &&
+ strcmp(buffer, PARTITION_STATUS_CORRUPTED) != 0 &&
+ strcmp(buffer, PARTITION_STATUS_FAILED) != 0) {
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int set_upgrade_progress_status(int status)
+{
+ /* status: -1 if upgrade fail, otherwise 0~100 */
+ if (status < -1 || status > 100) {
+ return -EINVAL;
+ }
+
+ /* clear contents of the file first */
+ if (truncate(UPGRADE_PROGRESS_STATUS_PATH, 0) == -1) {
+ int ferror = errno;
+ errno = 0;
+ return -ferror;
+ }
+
+ return sys_set_int(UPGRADE_PROGRESS_STATUS_PATH, status);
+}
+
+static int get_upgrade_progress_status(int *status)
+{
+ int ret_get_int = sys_get_int(UPGRADE_PROGRESS_STATUS_PATH, status);
+
+ if (ret_get_int < 0) {
+ return ret_get_int;
+ }
+
+ /* status: -1 if upgrade fail, otherwise 0~100 */
+ if (*status < -1 || *status > 100) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_upgrade_state(char *state)
+{
+ if (state == NULL)
+ return -EINVAL;
+
+ /* clear contents of the file first */
+ if (truncate(UPGRADE_STATE_PATH, 0) == -1) {
+ int ferror = errno;
+ errno = 0;
+ return -ferror;
+ }
+
+ return sys_set_str(UPGRADE_STATE_PATH, state);
+}
+
+static int get_upgrade_state(char *buffer, const int max_len)
+{
+ int ret = 0;
+
+ if (buffer == NULL)
+ return -EINVAL;
+
+ if (max_len < 1)
+ return -EINVAL;
+
+ ret = sys_get_str(UPGRADE_STATE_PATH, buffer, max_len - 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int board_init(void **data)
+{
+ hal_backend_device_board_funcs *device_board_funcs;
+
+ if (!data) {
+ _E("Invalid parameter");
+ return -EINVAL;
+ }
+
+ device_board_funcs = *(hal_backend_device_board_funcs **) data;
+ if (!device_board_funcs)
+ return -EINVAL;
+
+ device_board_funcs->get_device_serial_number = get_device_serial_number;
+
+ device_board_funcs->clear_boot_mode = clear_boot_mode;
+ device_board_funcs->get_boot_mode = get_boot_mode;
+
+ device_board_funcs->get_current_partition = get_current_partition;
+ device_board_funcs->switch_partition = switch_partition;
+ device_board_funcs->set_partition_ab_cloned = set_partition_ab_cloned;
+ device_board_funcs->clear_partition_ab_cloned = clear_partition_ab_cloned;
+ device_board_funcs->get_partition_ab_cloned = get_partition_ab_cloned;
+ device_board_funcs->set_partition_status = set_partition_status;
+ device_board_funcs->get_partition_status = get_partition_status;
+
+ device_board_funcs->set_upgrade_progress_status = set_upgrade_progress_status;
+ device_board_funcs->get_upgrade_progress_status = get_upgrade_progress_status;
+
+ device_board_funcs->set_upgrade_state = set_upgrade_state;
+ device_board_funcs->get_upgrade_state = get_upgrade_state;
+
+ return 0;
+}
+
+static int board_exit(void *data)
+{
+ return 0;
+}
+
+hal_backend EXPORT hal_backend_device_board_data = {
+ .name = "board",
+ .vendor = "VF2",
+ .init = board_init,
+ .exit = board_exit,
+ .major_version = 1,
+ .minor_version = 0,
+};