summaryrefslogtreecommitdiff
path: root/io-module/mts_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'io-module/mts_io.c')
-rw-r--r--io-module/mts_io.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/io-module/mts_io.c b/io-module/mts_io.c
index 1c9a5b6..995fb1d 100644
--- a/io-module/mts_io.c
+++ b/io-module/mts_io.c
@@ -40,6 +40,7 @@
#include <linux/spi/spi.h>
#include <linux/i2c/at24.h>
#include <linux/kmod.h>
+#include <linux/ctype.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -90,6 +91,18 @@ static struct gpio_pin *gpio_pins;
static DEFINE_MUTEX(mts_io_mutex);
+static unsigned int *timings_data = NULL;
+static unsigned int timings_data_size = 0;
+static unsigned int timings_data_index = 0;
+static time_t timings_data_stop_seconds = 0;
+static struct timer_list radio_reset_timer;
+static volatile int radio_reset_timer_is_start = 0;
+static struct timer_list radio_reset_available_timer;
+static volatile int radio_reset_available_timer_is_start = 0;
+static time_t time_now_secs();
+static void radio_reset_available_timer_callback(unsigned long data);
+static void radio_reset_timer_callback(unsigned long data);
+
/* generic GPIO support */
#include "gpio.c"
@@ -267,6 +280,30 @@ static ssize_t mts_attr_store_radio_reset(struct device *dev,
return -EINVAL;
}
+ /* check reset timings is enabled */
+ if (NULL != timings_data) {
+ /* check reset timer is started */
+ if (radio_reset_timer_is_start == 1) {
+ log_info("radio reset timer is running. \n");
+ return count;
+ }
+
+ /* check reset timer available is started */
+ if (radio_reset_available_timer_is_start == 1) {
+ del_timer(&radio_reset_available_timer);
+ radio_reset_available_timer_is_start = 0;
+ }
+
+ /* reset timer not started, start it */
+ mod_timer(&radio_reset_timer, jiffies + msecs_to_jiffies((timings_data[timings_data_index]) * 1000));
+ //log_info("radio reset timer is start = [%d]\n", time_now_secs());
+ /* save timings_data_stop_seconds */
+ timings_data_stop_seconds = timings_data[timings_data_index] + time_now_secs();
+ radio_reset_timer_is_start = 1;
+ }
+
+ log_info("radio is reset\n");
+
pin = gpio_pin_by_name("RADIO_RESET");
if (!pin) {
@@ -294,6 +331,211 @@ static DEVICE_ATTR_MTS(dev_attr_radio_reset, "radio-reset",
static DEVICE_ATTR_MTS(dev_attr_radio_power, "radio-power",
mts_attr_show_gpio_pin, mts_attr_store_gpio_pin);
+/* backoff-timers */
+static time_t time_now_secs()
+{
+ struct timespec ts = current_kernel_time();
+ return ts.tv_sec;
+}
+
+static void radio_reset_available_timer_callback( unsigned long data )
+{
+ /* do your timer stuff here */
+ //log_info("radio_reset_available_timer_callback\n");
+ //log_info("radio reset available timer is stop = [%d]\n", time_now_secs());
+
+ /* zero timings_data_index */
+ timings_data_index = 0;
+ //log_info("timings data index is zero = [%d]\n", timings_data_index);
+ radio_reset_available_timer_is_start = 0;
+}
+
+static void radio_reset_timer_callback( unsigned long data )
+{
+ /* do your timer stuff here */
+ //log_info("radio_reset_timer_callback\n");
+ //log_info("radio reset timer is stop = [%d]\n", time_now_secs());
+
+ /* increment timings_data_index */
+ timings_data_index++;
+ if(timings_data_index >= timings_data_size) {
+ timings_data_index = timings_data_size-1;
+ }
+
+ //log_info("timings data index = [%d]\n", timings_data_index);
+
+ /* reset available timer not started, start it */
+ mod_timer(&radio_reset_available_timer, jiffies + msecs_to_jiffies((timings_data[timings_data_index]) * 1000));
+ //log_info("radio reset available timer is start = [%d]\n", time_now_secs());
+ radio_reset_available_timer_is_start = 1;
+ radio_reset_timer_is_start = 0;
+}
+
+static ssize_t mts_attr_store_radio_reset_backoffs(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ char *timings_data_str = NULL;
+ const char delimiter[] = " ";
+ char * pch = NULL;
+ unsigned int size = 0;
+
+ /* free previous timings_data */
+ if (NULL != timings_data) {
+ /* stop timers */
+ del_timer(&radio_reset_timer);
+ del_timer(&radio_reset_available_timer);
+ timings_data_index = 0;
+ radio_reset_timer_is_start = 0;
+ radio_reset_available_timer_is_start = 0;
+
+ //log_info("free previous timings_data\n");
+ kfree(timings_data);
+ timings_data = NULL;
+ timings_data_size = 0;
+ }
+
+ /* make a copy */
+ if( NULL == (timings_data_str = kmalloc(strlen(buf), GFP_KERNEL)) ){
+ log_error("can`t allocate memory\n");
+ return -EINVAL;
+ }
+
+ memcpy(timings_data_str, buf, strlen(buf));
+
+ /* get number of tokens */
+ while (NULL != (pch = strsep (&timings_data_str, delimiter))) {
+ int value = 0;
+ sscanf(pch, "%d", &value);
+ if (value > 0){
+ size++;
+ if (NULL == timings_data) {
+ /* make alloc */
+ if (NULL == (timings_data = kmalloc(sizeof(unsigned int), GFP_KERNEL))) {
+ log_error("can`t allocate memory\n");
+ goto free;
+ }
+ } else {
+ /* make realloc */
+ if (NULL == (timings_data = krealloc(timings_data, size * sizeof(unsigned int), GFP_KERNEL))) {
+ log_error("can`t allocate memory\n");
+ goto free;
+ }
+ }
+ /* save timings data */
+ sscanf(pch, "%d", &timings_data[size-1]);
+ }
+ }
+
+ timings_data_size = size;
+
+ if (NULL != timings_data_str) {
+ /* free timings_data_str */
+ kfree(timings_data_str);
+ }
+ return count;
+
+free:
+ if (NULL != timings_data_str) {
+ /* free timings_data_str */
+ kfree(timings_data_str);
+ }
+
+ if (NULL != timings_data) {
+ kfree(timings_data);
+ timings_data = NULL;
+ timings_data_size = 0;
+ }
+ return -EINVAL;
+}
+
+static ssize_t mts_attr_store_radio_reset_backoffs_index(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int value;
+ int err;
+
+ if (sscanf(buf, "%d", &value) != 1) {
+ return -EINVAL;
+ }
+
+ if ((value < 0) || (value >= timings_data_size)) {
+ log_error("incorrect data\n");
+ return -EINVAL;
+ }
+
+ /* stop timers */
+ del_timer(&radio_reset_timer);
+ del_timer(&radio_reset_available_timer);
+ radio_reset_timer_is_start = 0;
+ radio_reset_available_timer_is_start = 0;
+ timings_data_index = value;
+
+ return count;
+}
+
+static ssize_t mts_attr_show_radio_reset_backoffs(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ size_t i = 0;
+
+ if (NULL != timings_data) {
+ for(i = 0; i < timings_data_size; ++i) {
+ ret += sprintf(buf += strlen(buf), "%d ", timings_data[i]);
+ }
+ }
+
+ if (ret > 0) {
+ ret -= 1;
+ }
+
+ return ret;
+}
+
+static ssize_t mts_attr_show_radio_reset_backoff_index(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t value;
+
+ if (strcmp(attr->attr.name, "radio-reset-backoff-index") == 0) {
+ value = sprintf(buf, "%d", timings_data_index);
+ }
+ else {
+ log_error("attribute '%s' not found", attr->attr.name);
+ value = -1;
+ }
+
+ return value;
+}
+
+static ssize_t mts_attr_show_radio_reset_backoff_seconds(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t value;
+
+ if (strcmp(attr->attr.name, "radio-reset-backoff-seconds") == 0) {
+ if (radio_reset_timer_is_start == 1) {
+ value = sprintf(buf, "%d", (timings_data_stop_seconds - time_now_secs()));
+ } else {
+ value = sprintf(buf, "%d", 0);
+ }
+ } else {
+ log_error("attribute '%s' not found", attr->attr.name);
+ value = -1;
+ }
+
+ return value;
+}
+
+static DEVICE_ATTR_MTS(dev_attr_radio_reset_backoffs, "radio-reset-backoffs",
+ mts_attr_show_radio_reset_backoffs, mts_attr_store_radio_reset_backoffs);
+
+static DEVICE_ATTR_MTS(dev_attr_radio_reset_backoff_index, "radio-reset-backoff-index",
+ mts_attr_show_radio_reset_backoff_index, mts_attr_store_radio_reset_backoffs_index);
+
+static DEVICE_ATTR_RO_MTS(dev_attr_radio_reset_backoff_seconds, "radio-reset-backoff-seconds",
+ mts_attr_show_radio_reset_backoff_seconds);
+
/* shared gpio-based LEDs */
static DEVICE_ATTR_MTS(dev_attr_led_status, "led-status",
mts_attr_show_gpio_pin, mts_attr_store_gpio_pin);
@@ -621,11 +863,20 @@ static int __init mts_io_init(void)
// start the reset handler
reset_callback(NULL);
+ /* init timers */
+ setup_timer(&radio_reset_timer, radio_reset_timer_callback, 0);
+ setup_timer(&radio_reset_available_timer, radio_reset_available_timer_callback, 0);
+
return 0;
}
static void __exit mts_io_exit(void)
{
+ /* delete radio_reset_timer */
+ del_timer(&radio_reset_timer);
+ /* delete radio_reset_available_timer */
+ del_timer(&radio_reset_available_timer);
+
cancel_delayed_work_sync(&reset_work);
cleanup();