aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/osmo-bts-sysmo/Makefile.am6
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_eeprom.h19
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr.c163
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_mgr.h9
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_misc.c268
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_misc.h31
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_par.c226
-rw-r--r--src/osmo-bts-sysmo/misc/sysmobts_par.h26
9 files changed, 748 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index e62fc839..63bd30bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@ contrib/sysmobts-calib/sysmobts-calib
src/osmo-bts-sysmo/l1fwd-proxy
src/osmo-bts-sysmo/sysmobts
src/osmo-bts-sysmo/sysmobts-remote
+src/osmo-bts-sysmo/sysmobts-mgr
tests/atconfig
diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am
index ab3e706f..e69ee2ac 100644
--- a/src/osmo-bts-sysmo/Makefile.am
+++ b/src/osmo-bts-sysmo/Makefile.am
@@ -2,7 +2,9 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS)
LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) -lortp
-bin_PROGRAMS = sysmobts sysmobts-remote l1fwd-proxy
+EXTRA_DIST = misc/sysmobts_mgr.h misc/sysmobts_misc.h misc/sysmobts_par.h misc/sysmobts_eeprom.h
+
+bin_PROGRAMS = sysmobts sysmobts-remote l1fwd-proxy sysmobts-mgr
COMMON_SOURCES = main.c femtobts.c l1_if.c oml.c sysmobts_vty.c tch.c hw_misc.c
@@ -14,3 +16,5 @@ sysmobts_remote_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)
l1fwd_proxy_SOURCES = l1_fwd_main.c l1_transp_hw.c
l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD)
+
+sysmobts_mgr_SOURCES = misc/sysmobts_mgr.c misc/sysmobts_misc.c misc/sysmobts_par.c
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h b/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h
new file mode 100644
index 00000000..4d27d028
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_eeprom.h
@@ -0,0 +1,19 @@
+#ifndef _SYSMOBTS_EEPROM_H
+#define _SYSMOBTS_EEPROM_H
+
+#include <stdint.h>
+
+struct sysmobts_eeprom { /* offset */
+ uint8_t eth_mac[6]; /* 0-5 */
+ uint8_t _pad0[10]; /* 6-15 */
+ uint16_t clk_cal_fact; /* 16-17 */
+ uint8_t temp1_max; /* 18 */
+ uint8_t temp2_max; /* 19 */
+ uint32_t serial_nr; /* 20-23 */
+ uint32_t operational_hours; /* 24-27 */
+ uint32_t boot_count; /* 28-31 */
+ uint8_t _pad1[89]; /* 32-127 */
+ uint8_t gpg_key[128]; /* 121-249 */
+} __attribute__((packed));
+
+#endif
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
new file mode 100644
index 00000000..01d65ce7
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c
@@ -0,0 +1,163 @@
+/* Main program for SysmoBTS management daemon */
+
+/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/logging.h>
+
+#include "misc/sysmobts_misc.h"
+#include "misc/sysmobts_mgr.h"
+
+static int daemonize = 0;
+void *tall_mgr_ctx;
+
+/* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */
+#define TEMP_TIMER_SECS (6 * 3600)
+
+/* every 1 hours means 365*24 = 8760 EEprom writes per year (max) */
+#define HOURS_TIMER_SECS (1 * 3600)
+
+static struct osmo_timer_list temp_timer;
+static void check_temp_timer_cb(void *unused)
+{
+ sysmobts_check_temp();
+
+ osmo_timer_schedule(&temp_timer, TEMP_TIMER_SECS, 0);
+}
+
+static struct osmo_timer_list hours_timer;
+static void hours_timer_cb(void *unused)
+{
+ sysmobts_update_hours();
+
+ osmo_timer_schedule(&hours_timer, HOURS_TIMER_SECS, 0);
+}
+
+static void signal_handler(int signal)
+{
+ fprintf(stderr, "signal %u received\n", signal);
+
+ switch (signal) {
+ case SIGINT:
+ sysmobts_check_temp();
+ sysmobts_update_hours();
+ exit(0);
+ break;
+ case SIGABRT:
+ case SIGUSR1:
+ case SIGUSR2:
+ talloc_report_full(tall_mgr_ctx, stderr);
+ break;
+ default:
+ break;
+ }
+}
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/logging.h>
+
+static struct log_info_cat mgr_log_info_cat[] = {
+ [DTEMP] = {
+ .name = "DTEMP",
+ .description = "Temperature monitoring",
+ .color = "\033[1;35m",
+ .enabled = 1, .loglevel = LOGL_INFO,
+ },
+ [DFW] = {
+ .name = "DFW",
+ .description = "DSP/FPGA firmware management",
+ .color = "\033[1;36m",
+ .enabled = 1, .loglevel = LOGL_INFO,
+ },
+};
+
+static const struct log_info mgr_log_info = {
+ .cat = mgr_log_info_cat,
+ .num_cat = ARRAY_SIZE(mgr_log_info_cat),
+};
+
+static int mgr_log_init(const char *category_mask)
+{
+ osmo_init_logging(&mgr_log_info);
+
+ if (category_mask)
+ log_parse_category_mask(osmo_stderr_target, category_mask);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ void *tall_msgb_ctx;
+ int rc;
+
+ tall_mgr_ctx = talloc_named_const(NULL, 1, "bts manager");
+ tall_msgb_ctx = talloc_named_const(tall_mgr_ctx, 1, "msgb");
+ msgb_set_talloc_ctx(tall_msgb_ctx);
+
+ //handle_options(argc, argv);
+
+ mgr_log_init(NULL);
+
+ signal(SIGINT, &signal_handler);
+ //signal(SIGABRT, &signal_handler);
+ signal(SIGUSR1, &signal_handler);
+ signal(SIGUSR2, &signal_handler);
+ osmo_init_ignore_signals();
+
+ if (daemonize) {
+ rc = osmo_daemonize();
+ if (rc < 0) {
+ perror("Error during daemonize");
+ exit(1);
+ }
+ }
+
+ /* start temperature check timer */
+ temp_timer.cb = check_temp_timer_cb;
+ check_temp_timer_cb(NULL);
+
+ /* start operational hours timer */
+ hours_timer.cb = hours_timer_cb;
+ hours_timer_cb(NULL);
+
+ while (1) {
+ log_reset_context();
+ osmo_select_main(0);
+ }
+}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
new file mode 100644
index 00000000..3b948b1c
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h
@@ -0,0 +1,9 @@
+#ifndef _SYSMOBTS_MGR_H
+#define _SYSMOBTS_MGR_H
+
+enum {
+ DTEMP,
+ DFW,
+};
+
+#endif
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
new file mode 100644
index 00000000..266eb00b
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c
@@ -0,0 +1,268 @@
+/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <time.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/application.h>
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/logging.h>
+
+#include "sysmobts_misc.h"
+#include "sysmobts_par.h"
+#include "sysmobts_mgr.h"
+
+
+/*********************************************************************
+ * Temperature handling
+ *********************************************************************/
+
+#define TEMP_PATH "/sys/class/hwmon/hwmon0/device%u_%s"
+
+static const char *temp_type_str[_NUM_TEMP_TYPES] = {
+ [SYSMOBTS_TEMP_INPUT] = "input",
+ [SYSMOBTS_TEMP_LOWEST] = "lowest",
+ [SYSMOBTS_TEMP_HIGHEST] = "highest",
+};
+
+int sysmobts_temp_get(enum sysmobts_temp_sensor sensor,
+ enum sysmobts_temp_type type)
+{
+ char buf[PATH_MAX];
+ char tempstr[8];
+ int fd, rc;
+
+ if (sensor < SYSMOBTS_TEMP_DIGITAL ||
+ sensor > SYSMOBTS_TEMP_RF)
+ return -EINVAL;
+
+ if (type > _NUM_TEMP_TYPES)
+ return -EINVAL;
+
+ snprintf(buf, sizeof(buf)-1, TEMP_PATH, sensor, temp_type_str[type]);
+ buf[sizeof(buf)-1] = '\0';
+
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ rc = read(fd, tempstr, sizeof(tempstr));
+ tempstr[sizeof(tempstr)-1] = '\0';
+ if (rc < 0) {
+ close(fd);
+ return rc;
+ }
+ if (rc == 0) {
+ close(fd);
+ return -EIO;
+ }
+
+ close(fd);
+
+ return atoi(tempstr);
+}
+
+static const struct {
+ const char *name;
+ enum sysmobts_temp_sensor sensor;
+ enum sysmobts_par ee_par;
+} temp_data[] = {
+ {
+ .name = "digital",
+ .sensor = SYSMOBTS_TEMP_DIGITAL,
+ .ee_par = SYSMOBTS_PAR_TEMP_DIG_MAX,
+ }, {
+ .name = "rf",
+ .sensor = SYSMOBTS_TEMP_RF,
+ .ee_par = SYSMOBTS_PAR_TEMP_RF_MAX,
+ }
+};
+
+void sysmobts_check_temp(void)
+{
+ int temp_old[ARRAY_SIZE(temp_data)];
+ int temp_hi[ARRAY_SIZE(temp_data)];
+ int temp_cur[ARRAY_SIZE(temp_data)];
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(temp_data); i++) {
+ temp_old[i] = sysmobts_par_get_int(temp_data[i].ee_par) * 1000;
+ temp_hi[i] = sysmobts_temp_get(temp_data[i].sensor,
+ SYSMOBTS_TEMP_HIGHEST);
+ temp_cur[i] = sysmobts_temp_get(temp_data[i].sensor,
+ SYSMOBTS_TEMP_INPUT);
+
+ if ((temp_cur[i] < 0 && temp_cur[i] > -1000) ||
+ (temp_hi[i] < 0 && temp_hi[i] > -1000)) {
+ LOGP(DTEMP, LOGL_ERROR, "Error reading temperature\n");
+ return;
+ }
+
+ LOGP(DTEMP, LOGL_DEBUG, "Current %s temperature: %d.%d C\n",
+ temp_data[i].name, temp_cur[i]/1000, temp_cur[i]%1000);
+
+ if (temp_hi[i] > temp_old[i]) {
+ LOGP(DTEMP, LOGL_NOTICE, "New maximum %s "
+ "temperature: %d.%d C\n", temp_data[i].name,
+ temp_hi[i]/1000, temp_hi[i]%1000);
+ rc = sysmobts_par_set_int(SYSMOBTS_PAR_TEMP_DIG_MAX,
+ temp_hi[0]/1000);
+ if (rc < 0)
+ LOGP(DTEMP, LOGL_ERROR, "error writing new %s "
+ "max temp %d (%s)\n", temp_data[i].name,
+ rc, strerror(errno));
+ }
+ }
+}
+
+/*********************************************************************
+ * Hours handling
+ *********************************************************************/
+static time_t last_update;
+
+int sysmobts_update_hours(void)
+{
+ time_t now = time(NULL);
+ int op_hrs;
+
+ /* first time after start of manager program */
+ if (last_update == 0) {
+ last_update = now;
+
+ op_hrs = sysmobts_par_get_int(SYSMOBTS_PAR_HOURS);
+ if (op_hrs < 0) {
+ LOGP(DTEMP, LOGL_ERROR, "Unable to read "
+ "operational hours: %d (%s)\n", op_hrs,
+ strerror(errno));
+ return op_hrs;
+ }
+
+ LOGP(DTEMP, LOGL_INFO, "Total hours of Operation: %u\n",
+ op_hrs);
+
+ return 0;
+ }
+
+ if (now >= last_update + 3600) {
+ int rc;
+ op_hrs = sysmobts_par_get_int(SYSMOBTS_PAR_HOURS);
+ if (op_hrs < 0) {
+ LOGP(DTEMP, LOGL_ERROR, "Unable to read "
+ "operational hours: %d (%s)\n", op_hrs,
+ strerror(errno));
+ return op_hrs;
+ }
+
+ /* number of hours to increase */
+ op_hrs += (now-last_update)/3600;
+
+ LOGP(DTEMP, LOGL_INFO, "Total hours of Operation: %u\n",
+ op_hrs);
+
+ rc = sysmobts_par_set_int(SYSMOBTS_PAR_HOURS, op_hrs);
+ if (rc < 0)
+ return rc;
+
+ last_update = now;
+ }
+
+ return 0;
+}
+
+/*********************************************************************
+ * Firmware reloading
+ *********************************************************************/
+
+#define SYSMOBTS_FW_PATH "/lib/firmware"
+
+static const char *fw_names[_NUM_FW] = {
+ [SYSMOBTS_FW_FPGA] = "sysmobts-v2.bit",
+ [SYSMOBTS_FW_DSP] = "sysmobts-v2.out",
+};
+static const char *fw_devs[_NUM_FW] = {
+ [SYSMOBTS_FW_FPGA] = "/dev/fpgadl_par0",
+ [SYSMOBTS_FW_DSP] = "/dev/dspdl_dm644x_0",
+};
+
+int sysmobts_firmware_reload(enum sysmobts_firmware_type type)
+{
+ char name[PATH_MAX];
+ uint8_t buf[1024];
+ int fd_in, fd_out, rc;
+
+ if (type >= _NUM_FW)
+ return -EINVAL;
+
+ snprintf(name, sizeof(name)-1, "%s/%s",
+ SYSMOBTS_FW_PATH, fw_names[type]);
+ name[sizeof(name)-1] = '\0';
+
+ fd_in = open(name, O_RDONLY);
+ if (fd_in < 0) {
+ LOGP(DFW, LOGL_ERROR, "unable ot open firmware file %s: %s\n",
+ name, strerror(errno));
+ return fd_in;
+ }
+
+ fd_out = open(fw_devs[type], O_WRONLY);
+ if (fd_out < 0) {
+ LOGP(DFW, LOGL_ERROR, "unable ot open firmware device %s: %s\n",
+ fw_devs[type], strerror(errno));
+ close(fd_in);
+ return fd_out;
+ }
+
+ while ((rc = read(fd_in, buf, sizeof(buf)))) {
+ int written;
+
+ if (rc < 0) {
+ LOGP(DFW, LOGL_ERROR, "error %d during read "
+ "from %s: %s\n", rc, name, strerror(errno));
+ close(fd_in);
+ close(fd_out);
+ return -EIO;
+ }
+
+ written = write(fd_out, buf, rc);
+ if (written < rc) {
+ LOGP(DFW, LOGL_ERROR, "short write during "
+ "fw write to %s\n", fw_devs[type]);
+ close(fd_in);
+ close(fd_out);
+ return -EIO;
+ }
+ }
+
+ close(fd_in);
+ close(fd_out);
+
+ return 0;
+}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h
new file mode 100644
index 00000000..13d0add3
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h
@@ -0,0 +1,31 @@
+#ifndef _SYSMOBTS_MISC_H
+#define _SYSMOBTS_MISC_H
+
+enum sysmobts_temp_sensor {
+ SYSMOBTS_TEMP_DIGITAL = 1,
+ SYSMOBTS_TEMP_RF = 2,
+};
+
+enum sysmobts_temp_type {
+ SYSMOBTS_TEMP_INPUT,
+ SYSMOBTS_TEMP_LOWEST,
+ SYSMOBTS_TEMP_HIGHEST,
+ _NUM_TEMP_TYPES
+};
+
+int sysmobts_temp_get(enum sysmobts_temp_sensor sensor,
+ enum sysmobts_temp_type type);
+
+void sysmobts_check_temp(void);
+
+int sysmobts_update_hours(void);
+
+enum sysmobts_firmware_type {
+ SYSMOBTS_FW_FPGA,
+ SYSMOBTS_FW_DSP,
+ _NUM_FW
+};
+
+int sysmobts_firmware_reload(enum sysmobts_firmware_type type);
+
+#endif
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_par.c b/src/osmo-bts-sysmo/misc/sysmobts_par.c
new file mode 100644
index 00000000..3399e4ff
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_par.c
@@ -0,0 +1,226 @@
+/* sysmobts - access to hardware related parameters */
+
+/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sysmobts_eeprom.h"
+#include "sysmobts_par.h"
+
+#define EEPROM_PATH "/sys/devices/platform/i2c_davinci.1/i2c-1/1-0050/eeprom"
+
+
+static struct {
+ int read;
+ struct sysmobts_eeprom ee;
+} g_ee;
+
+static struct sysmobts_eeprom *get_eeprom(int update_rqd)
+{
+ if (update_rqd || g_ee.read == 0) {
+ int fd, rc;
+
+ fd = open(EEPROM_PATH, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ rc = read(fd, &g_ee.ee, sizeof(g_ee.ee));
+
+ close(fd);
+
+ if (rc < sizeof(g_ee.ee))
+ return NULL;
+
+ g_ee.read = 1;
+ }
+
+ return &g_ee.ee;
+}
+
+static int set_eeprom(struct sysmobts_eeprom *ee)
+{
+ int fd, rc;
+
+ memcpy(&g_ee.ee, ee, sizeof(*ee));
+
+ fd = open(EEPROM_PATH, O_WRONLY);
+ if (fd < 0)
+ return fd;
+
+ rc = write(fd, ee, sizeof(*ee));
+ if (rc < sizeof(*ee)) {
+ close(fd);
+ return -EIO;
+ }
+
+ close(fd);
+
+ return 0;
+}
+
+int sysmobts_par_get_int(enum sysmobts_par par)
+{
+ int ret;
+ struct sysmobts_eeprom *ee = get_eeprom(0);
+
+ if (!ee)
+ return -EIO;
+
+ if (par >= _NUM_SYSMOBTS_PAR)
+ return -ENODEV;
+
+ switch (par) {
+ case SYSMOBTS_PAR_CLK_FACTORY:
+ ret = ee->clk_cal_fact;
+ break;
+ case SYSMOBTS_PAR_TEMP_DIG_MAX:
+ ret = ee->temp1_max;
+ break;
+ case SYSMOBTS_PAR_TEMP_RF_MAX:
+ ret = ee->temp2_max;
+ break;
+ case SYSMOBTS_PAR_SERNR:
+ ret = ee->serial_nr;
+ break;
+ case SYSMOBTS_PAR_HOURS:
+ ret = ee->operational_hours;
+ break;
+ case SYSMOBTS_PAR_BOOTS:
+ ret = ee->boot_count;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int sysmobts_par_set_int(enum sysmobts_par par, unsigned int val)
+{
+ struct sysmobts_eeprom *ee = get_eeprom(1);
+
+ if (!ee)
+ return -EIO;
+
+ if (par >= _NUM_SYSMOBTS_PAR)
+ return -ENODEV;
+
+ switch (par) {
+ case SYSMOBTS_PAR_CLK_FACTORY:
+ ee->clk_cal_fact = val;
+ break;
+ case SYSMOBTS_PAR_TEMP_DIG_MAX:
+ ee->temp1_max = val;
+ break;
+ case SYSMOBTS_PAR_TEMP_RF_MAX:
+ ee->temp2_max = val;
+ break;
+ case SYSMOBTS_PAR_SERNR:
+ ee->serial_nr = val;
+ break;
+ case SYSMOBTS_PAR_HOURS:
+ ee->operational_hours = val;
+ break;
+ case SYSMOBTS_PAR_BOOTS:
+ ee->boot_count = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ set_eeprom(ee);
+
+ return 0;
+}
+
+int sysmobts_par_get_buf(enum sysmobts_par par, uint8_t *buf,
+ unsigned int size)
+{
+ uint8_t *ptr;
+ unsigned int len;
+ struct sysmobts_eeprom *ee = get_eeprom(0);
+
+ if (!ee)
+ return -EIO;
+
+ if (par >= _NUM_SYSMOBTS_PAR)
+ return -ENODEV;
+
+ switch (par) {
+ case SYSMOBTS_PAR_MAC:
+ ptr = ee->eth_mac;
+ len = sizeof(ee->eth_mac);
+ break;
+ case SYSMOBTS_PAR_KEY:
+ ptr = ee->gpg_key;
+ len = sizeof(ee->gpg_key);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (size < len)
+ len = size;
+ memcpy(buf, ptr, len);
+
+ return len;
+}
+
+int sysmobts_par_set_buf(enum sysmobts_par par, const uint8_t *buf,
+ unsigned int size)
+{
+ uint8_t *ptr;
+ unsigned int len;
+ struct sysmobts_eeprom *ee = get_eeprom(0);
+
+ if (!ee)
+ return -EIO;
+
+ if (par >= _NUM_SYSMOBTS_PAR)
+ return -ENODEV;
+
+ switch (par) {
+ case SYSMOBTS_PAR_MAC:
+ ptr = ee->eth_mac;
+ len = sizeof(ee->eth_mac);
+ break;
+ case SYSMOBTS_PAR_KEY:
+ ptr = ee->gpg_key;
+ len = sizeof(ee->gpg_key);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (len < size)
+ size = len;
+
+ memcpy(ptr, buf, size);
+
+ return len;
+}
diff --git a/src/osmo-bts-sysmo/misc/sysmobts_par.h b/src/osmo-bts-sysmo/misc/sysmobts_par.h
new file mode 100644
index 00000000..85a38abc
--- /dev/null
+++ b/src/osmo-bts-sysmo/misc/sysmobts_par.h
@@ -0,0 +1,26 @@
+#ifndef _SYSMOBTS_PAR_H
+#define _SYSMOBTS_PAR_H
+
+#include <stdint.h>
+
+enum sysmobts_par {
+ SYSMOBTS_PAR_MAC,
+ SYSMOBTS_PAR_CLK_FACTORY,
+ SYSMOBTS_PAR_TEMP_DIG_MAX,
+ SYSMOBTS_PAR_TEMP_RF_MAX,
+ SYSMOBTS_PAR_SERNR,
+ SYSMOBTS_PAR_HOURS,
+ SYSMOBTS_PAR_BOOTS,
+ SYSMOBTS_PAR_KEY,
+ _NUM_SYSMOBTS_PAR
+};
+
+
+int sysmobts_par_get_int(enum sysmobts_par par);
+int sysmobts_par_set_int(enum sysmobts_par par, unsigned int val);
+int sysmobts_par_get_buf(enum sysmobts_par par, uint8_t *buf,
+ unsigned int size);
+int sysmobts_par_set_buf(enum sysmobts_par par, const uint8_t *buf,
+ unsigned int size);
+
+#endif