#include "buttons.h" extern ssize_t mts_attr_show_gpio_pin(struct device *dev, struct device_attribute *attr, char *buf); extern struct gpio_pin *gpio_pin_by_attr_name(const char *name); static button_info_pt *buttons = NULL; struct gpio_pin *gpio_pin_by_button_name(const char *button_name) { button_info_pt *pbutton; for (pbutton = buttons; *pbutton != NULL; pbutton++) { if (!strcmp(pbutton[0]->name, button_name)) { return gpio_pin_by_attr_name(pbutton[0]->label_pin); } } log_error("Button named %s not found", button_name); return NULL; } static button_info_t *button_by_monitor_name(const char *label_monitor) { button_info_pt *pbutton; for (pbutton = buttons; *pbutton != NULL; pbutton++) { if (!strcmp(pbutton[0]->label_monitor, label_monitor)) { return pbutton[0]; } } log_error("Button with %s monitor label is not found", label_monitor); return NULL; } static button_info_t *button_by_monitor_intervals_name(const char *label_monitor_intervals) { button_info_pt *pbutton; for (pbutton = buttons; *pbutton != NULL; pbutton++) { if (!strcmp(pbutton[0]->label_monitor_intervals, label_monitor_intervals)) { return pbutton[0]; } } log_error("Button with %s monitor intervals label is not found", label_monitor_intervals); return NULL; } ssize_t mts_attr_show_button_monitor_intervals(struct device *dev, struct device_attribute *attr, char *buf) { int ret; button_info_t *button = button_by_monitor_intervals_name(attr->attr.name); if (!button) { return -ENODEV; } mutex_lock(&mts_io_mutex); ret = sprintf(buf, "%d %d\n", button->short_interval / BUTTON_CHECK_PER_SEC, button->long_interval / BUTTON_CHECK_PER_SEC); mutex_unlock(&mts_io_mutex); return ret; } ssize_t mts_attr_store_button_monitor_intervals(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int short_int; int long_int; button_info_t *button = button_by_monitor_intervals_name(attr->attr.name); if (sscanf(buf, "%i %i", &short_int, &long_int) != 2) { return -EINVAL; } if (!button) { return -ENODEV; } mutex_lock(&mts_io_mutex); button->short_interval = short_int * BUTTON_CHECK_PER_SEC; button->long_interval = long_int * BUTTON_CHECK_PER_SEC; mutex_unlock(&mts_io_mutex); return count; } ssize_t mts_attr_show_button_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 %d %d\n", button->pid, button->short_signal, button->long_signal, button->extra_long_signal); mutex_unlock(&mts_io_mutex); return ret; } ssize_t mts_attr_store_button_monitor(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { pid_t pid; int short_signal; int long_signal; int extra_long_signal; int result = sscanf(buf, "%i %i %i %i", &pid, &short_signal, &long_signal, &extra_long_signal); button_info_t *button = button_by_monitor_name(attr->attr.name); if (!button) { return -ENODEV; } if (result < 3 || result > 4) { return -EINVAL; } if(result == 3) { mutex_lock(&mts_io_mutex); button->pid = pid; button->short_signal = short_signal; button->long_signal = long_signal; mutex_unlock(&mts_io_mutex); } else { mutex_lock(&mts_io_mutex); button->pid = pid; button->short_signal = short_signal; button->long_signal = long_signal; button->extra_long_signal = extra_long_signal; mutex_unlock(&mts_io_mutex); } return count; } static void button_worker(struct work_struct *ignored); static DECLARE_DELAYED_WORK(button_work, button_worker); static void button_worker(struct work_struct *ignored) { struct gpio_pin *pin; struct pid *vpid; int button_pressed = 0; button_info_pt *pbutton; mutex_lock(&mts_io_mutex); for (pbutton = buttons; *pbutton != NULL; pbutton++) { button_pressed = 0; vpid = NULL; pin = gpio_pin_by_button_name(pbutton[0]->name); if (pin) { if (pin->do_gpio_desc) { button_pressed = !gpiod_get_value(pin->desc); } else { button_pressed = !gpio_get_value(pin->pin.gpio); } } if (pbutton[0]->pid > 0) { vpid = find_vpid(pbutton[0]->pid); } if (vpid) { if (button_pressed) { pbutton[0]->pressed_count++; } else { // The button is not pressed if (pbutton[0]->pressed_count > 0 && pbutton[0]->pressed_count < pbutton[0]->short_interval) { log_debug("Button %s short signal", pbutton[0]->name); kill_pid(vpid, pbutton[0]->short_signal, 1); } else if (pbutton[0]->pressed_count >= pbutton[0]->short_interval && pbutton[0]->pressed_count < pbutton[0]->long_interval) { log_debug("Button %s long signal", pbutton[0]->name); kill_pid(vpid, pbutton[0]->long_signal, 1); } pbutton[0]->pressed_count = 0; pbutton[0]->sent_extra_long = false; } if (pbutton[0]->pressed_count >= pbutton[0]->long_interval && ! pbutton[0]->sent_extra_long) { log_debug("Button %s extra long signal", pbutton[0]->name); kill_pid(vpid, pbutton[0]->extra_long_signal, 1); pbutton[0]->sent_extra_long = true; } } else { pbutton[0]->pressed_count = 0; } } mutex_unlock(&mts_io_mutex); schedule_delayed_work(&button_work, BUTTON_INTERVAL); } int set_buttons (button_info_pt* platform_buttons) { if (platform_buttons == NULL) { log_error("Null pointer error"); return -EINVAL; } mutex_lock(&mts_io_mutex); if (buttons != NULL) { log_warning("Buttons structure was initialized more then once"); } buttons = platform_buttons; mutex_unlock(&mts_io_mutex); return 0; } void init_buttons(void) { if (buttons == NULL) { log_error("Button structure hasn't been set. Use default"); set_buttons(default_buttons); } button_worker(NULL); } void cleanup_buttons(void) { cancel_delayed_work_sync(&button_work); } // Reset button is common for all devices button_info_t reset_button = { .name = "Reset Button", .label_pin = "reset", .label_monitor = "reset-monitor", .label_monitor_intervals = "reset-monitor-intervals", /* Signals */ .short_signal = SIGUSR1, .long_signal = SIGUSR2, .short_signal = SIGHUP, /* Intervals */ .short_interval = BUTTON_HOLD_COUNT, .long_interval = BUTTON_LONG_HOLD_COUNT, }; DEVICE_ATTR_MTS(dev_attr_reset_monitor_intervals, reset_button.label_monitor_intervals, mts_attr_show_button_monitor_intervals, mts_attr_store_button_monitor_intervals); DEVICE_ATTR_MTS(dev_attr_reset_monitor, reset_button.label_monitor, mts_attr_show_button_monitor, mts_attr_store_button_monitor); DEVICE_ATTR_RO_MTS(dev_attr_reset, reset_button.label_pin, mts_attr_show_gpio_pin); button_info_pt default_buttons[] = { &reset_button, NULL, };