1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#include "mts_supercap.h"
extern struct gpio_pin *gpio_pin_by_attr_name(const char *name);
static supercap_info_t supercap = {
.name = "Super Cap",
.label_monitor = "supercap-monitor",
.signal = SIGPWR,
.pid = 0,
.pwf_count = 0,
.pin_is_one = 0,
};
ssize_t mts_attr_show_supercap_monitor(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int ret;
//button_info_t *button = button_by_monitor_name(attr->attr.name);
//if (!button) {
// return -ENODEV;
//}
mutex_lock(&mts_io_mutex);
ret = sprintf(buf, "%d %d\n", supercap.pid, supercap.signal);
mutex_unlock(&mts_io_mutex);
return ret;
}
ssize_t mts_attr_store_supercap_monitor(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
pid_t pid;
int signal;
int result = sscanf(buf, "%i %i", &pid, &signal);
//button_info_t *button = button_by_monitor_name(attr->attr.name);
//if (!button) {
// return -ENODEV;
//}
if (result != 2) {
return -EINVAL;
}
if(result == 2) {
mutex_lock(&mts_io_mutex);
supercap.pid = pid;
supercap.signal = signal;
mutex_unlock(&mts_io_mutex);
}
return count;
}
static void supercap_worker(struct work_struct *ignored);
static DECLARE_DELAYED_WORK(supercap_work, supercap_worker);
static void supercap_worker(struct work_struct *ignored)
{
struct gpio_pin *pin;
struct pid *vpid;
int running_on_cap = 0;
pin = gpio_pin_by_attr_name("power-fail");
if (pin) {
running_on_cap = !gpio_get_value(pin->pin.gpio);
}
if (supercap.pid > 0) {
vpid = find_vpid(supercap.pid);
}
if (vpid) {
if (running_on_cap == 0 && supercap.pwf_count == 0) {
schedule_delayed_work(&supercap_work, SUPERCAP_CHECK_INTERVAL);
}
else if ( (supercap.pwf_count >= 0) && (supercap.pwf_count < SUPERCAP_TOTAL_INTERVALS) ) {
/* check if 90% of checks were running_on_cap == 1 */
supercap.pwf_count++;
if (running_on_cap == 1) {
supercap.pin_is_one++;
}
if (supercap.pin_is_one >= 45) {
/* send configured signal to reset handler pid */
log_debug("Super Cap positives %d long signal", supercap.pin_is_one);
kill_pid(vpid, supercap.signal, 1);
/* reset and start over since hit the reset condition (maybe we should clean up and go away?) */
supercap.pwf_count = 0;
supercap.pin_is_one = 0;
}
}
else if (supercap.pwf_count == SUPERCAP_TOTAL_INTERVALS) {
/* reset and start over since didn't reach 90% at total intervals */
supercap.pwf_count = 0;
supercap.pin_is_one = 0;
}
} /* vpid */
schedule_delayed_work(&supercap_work, SUPERCAP_CHECK_INTERVAL);
}
void init_supercap_worker(void) {
supercap_worker(NULL);
}
void cleanup_sepercap_worker(void) {
cancel_delayed_work_sync(&supercap_work);
}
DEVICE_ATTR_MTS(dev_attr_supercap_monitor,
supercap.label_monitor,
mts_attr_show_supercap_monitor,
mts_attr_store_supercap_monitor);
|