^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Generic Counter interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2018 William Breathitt Gray
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/counter.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/idr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/printk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) const char *const counter_count_direction_str[2] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) [COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) EXPORT_SYMBOL_GPL(counter_count_direction_str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) const char *const counter_count_mode_str[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) [COUNTER_COUNT_MODE_NORMAL] = "normal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) EXPORT_SYMBOL_GPL(counter_count_mode_str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ssize_t counter_signal_enum_read(struct counter_device *counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct counter_signal *signal, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) const struct counter_signal_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) size_t index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (!e->get)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) err = e->get(counter, signal, &index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (index >= e->num_items)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return sprintf(buf, "%s\n", e->items[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) EXPORT_SYMBOL_GPL(counter_signal_enum_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ssize_t counter_signal_enum_write(struct counter_device *counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct counter_signal *signal, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) const struct counter_signal_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ssize_t index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!e->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) index = __sysfs_match_string(e->items, e->num_items, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) err = e->set(counter, signal, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) EXPORT_SYMBOL_GPL(counter_signal_enum_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ssize_t counter_signal_enum_available_read(struct counter_device *counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct counter_signal *signal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) void *priv, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) const struct counter_signal_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (!e->num_items)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) for (i = 0; i < e->num_items; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) len += sprintf(buf + len, "%s\n", e->items[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) EXPORT_SYMBOL_GPL(counter_signal_enum_available_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ssize_t counter_count_enum_read(struct counter_device *counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct counter_count *count, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) const struct counter_count_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) size_t index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (!e->get)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) err = e->get(counter, count, &index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (index >= e->num_items)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return sprintf(buf, "%s\n", e->items[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) EXPORT_SYMBOL_GPL(counter_count_enum_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) ssize_t counter_count_enum_write(struct counter_device *counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct counter_count *count, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) const struct counter_count_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ssize_t index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (!e->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) index = __sysfs_match_string(e->items, e->num_items, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) err = e->set(counter, count, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) EXPORT_SYMBOL_GPL(counter_count_enum_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) ssize_t counter_count_enum_available_read(struct counter_device *counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct counter_count *count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) void *priv, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) const struct counter_count_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (!e->num_items)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) for (i = 0; i < e->num_items; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) len += sprintf(buf + len, "%s\n", e->items[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) EXPORT_SYMBOL_GPL(counter_count_enum_available_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) ssize_t counter_device_enum_read(struct counter_device *counter, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) const struct counter_device_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) size_t index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (!e->get)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) err = e->get(counter, &index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (index >= e->num_items)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return sprintf(buf, "%s\n", e->items[index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) EXPORT_SYMBOL_GPL(counter_device_enum_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ssize_t counter_device_enum_write(struct counter_device *counter, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) const struct counter_device_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) ssize_t index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!e->set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) index = __sysfs_match_string(e->items, e->num_items, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) err = e->set(counter, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) EXPORT_SYMBOL_GPL(counter_device_enum_write);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) ssize_t counter_device_enum_available_read(struct counter_device *counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) void *priv, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) const struct counter_device_enum_ext *const e = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (!e->num_items)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) for (i = 0; i < e->num_items; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) len += sprintf(buf + len, "%s\n", e->items[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) struct counter_attr_parm {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) struct counter_device_attr_group *group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) const char *prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) ssize_t (*show)(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) char *buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) ssize_t (*store)(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) const char *buf, size_t len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) void *component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct counter_device_attr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) struct device_attribute dev_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct list_head l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) void *component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static int counter_attribute_create(const struct counter_attr_parm *const parm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct counter_device_attr *counter_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct device_attribute *dev_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct list_head *const attr_list = &parm->group->attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* Allocate a Counter device attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) counter_attr = kzalloc(sizeof(*counter_attr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (!counter_attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) dev_attr = &counter_attr->dev_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) sysfs_attr_init(&dev_attr->attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* Configure device attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) dev_attr->attr.name = kasprintf(GFP_KERNEL, "%s%s", parm->prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) parm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (!dev_attr->attr.name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) goto err_free_counter_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (parm->show) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) dev_attr->attr.mode |= 0444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) dev_attr->show = parm->show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (parm->store) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) dev_attr->attr.mode |= 0200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) dev_attr->store = parm->store;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* Store associated Counter component with attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) counter_attr->component = parm->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* Keep track of the attribute for later cleanup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) list_add(&counter_attr->l, attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) parm->group->num_attr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) err_free_counter_attr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) kfree(counter_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) #define to_counter_attr(_dev_attr) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) container_of(_dev_attr, struct counter_device_attr, dev_attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) struct counter_signal_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) struct counter_signal *signal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static const char *const counter_signal_value_str[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) [COUNTER_SIGNAL_LOW] = "low",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) [COUNTER_SIGNAL_HIGH] = "high"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) static ssize_t counter_signal_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) const struct counter_signal_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct counter_signal *const signal = component->signal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) enum counter_signal_value val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) err = counter->ops->signal_read(counter, signal, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return sprintf(buf, "%s\n", counter_signal_value_str[val]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct counter_name_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static ssize_t counter_device_attr_name_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) const struct counter_name_unit *const comp = to_counter_attr(attr)->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return sprintf(buf, "%s\n", comp->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static int counter_name_attribute_create(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) const char *const name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct counter_name_unit *name_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* Skip if no name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /* Allocate name attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) name_comp = kmalloc(sizeof(*name_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (!name_comp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) name_comp->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* Allocate Signal name attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) parm.name = "name";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) parm.show = counter_device_attr_name_show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) parm.store = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) parm.component = name_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) goto err_free_name_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) err_free_name_comp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) kfree(name_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) struct counter_signal_ext_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) struct counter_signal *signal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) const struct counter_signal_ext *ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static ssize_t counter_signal_ext_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) const struct counter_signal_ext_unit *const comp = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) const struct counter_signal_ext *const ext = comp->ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return ext->read(dev_get_drvdata(dev), comp->signal, ext->priv, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static ssize_t counter_signal_ext_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) const struct counter_signal_ext_unit *const comp = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) const struct counter_signal_ext *const ext = comp->ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return ext->write(dev_get_drvdata(dev), comp->signal, ext->priv, buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) static void counter_device_attr_list_free(struct list_head *attr_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) struct counter_device_attr *p, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) list_for_each_entry_safe(p, n, attr_list, l) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* free attribute name and associated component memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) kfree(p->dev_attr.attr.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) kfree(p->component);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) list_del(&p->l);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) static int counter_signal_ext_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) struct counter_signal *const signal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) const size_t num_ext = signal->num_ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) const struct counter_signal_ext *ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) struct counter_signal_ext_unit *signal_ext_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /* Create an attribute for each extension */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) for (i = 0 ; i < num_ext; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) ext = signal->ext + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* Allocate signal_ext attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) signal_ext_comp = kmalloc(sizeof(*signal_ext_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (!signal_ext_comp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) signal_ext_comp->signal = signal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) signal_ext_comp->ext = ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /* Allocate a Counter device attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) parm.name = ext->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) parm.show = (ext->read) ? counter_signal_ext_show : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) parm.store = (ext->write) ? counter_signal_ext_store : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) parm.component = signal_ext_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) kfree(signal_ext_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) err_free_attr_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static int counter_signal_attributes_create(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) const struct counter_device *const counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct counter_signal *const signal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) struct counter_signal_unit *signal_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) /* Allocate Signal attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) signal_comp = kmalloc(sizeof(*signal_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (!signal_comp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) signal_comp->signal = signal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) /* Create main Signal attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) parm.name = "signal";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) parm.show = (counter->ops->signal_read) ? counter_signal_show : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) parm.store = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) parm.component = signal_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) kfree(signal_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /* Create Signal name attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) err = counter_name_attribute_create(group, signal->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) /* Register Signal extension attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) err = counter_signal_ext_register(group, signal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) err_free_attr_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) static int counter_signals_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) struct counter_device_attr_group *const groups_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) const struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) const size_t num_signals = counter->num_signals;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) struct counter_signal *signal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) /* Register each Signal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) for (i = 0; i < num_signals; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) signal = counter->signals + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) /* Generate Signal attribute directory name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) name = kasprintf(GFP_KERNEL, "signal%d", signal->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (!name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) goto err_free_attr_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) groups_list[i].attr_group.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) /* Create all attributes associated with Signal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) err = counter_signal_attributes_create(groups_list + i, counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) signal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) goto err_free_attr_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) err_free_attr_groups:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) kfree(groups_list[i].attr_group.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) counter_device_attr_list_free(&groups_list[i].attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) } while (i--);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static const char *const counter_synapse_action_str[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) [COUNTER_SYNAPSE_ACTION_NONE] = "none",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) [COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) [COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) [COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) struct counter_action_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct counter_synapse *synapse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) struct counter_count *count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) static ssize_t counter_action_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) const struct counter_action_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) struct counter_count *const count = component->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) struct counter_synapse *const synapse = component->synapse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) size_t action_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) enum counter_synapse_action action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) err = counter->ops->action_get(counter, count, synapse, &action_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) synapse->action = action_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) action = synapse->actions_list[action_index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return sprintf(buf, "%s\n", counter_synapse_action_str[action]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) static ssize_t counter_action_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) const struct counter_action_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct counter_synapse *const synapse = component->synapse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) size_t action_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) const size_t num_actions = synapse->num_actions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) enum counter_synapse_action action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) struct counter_count *const count = component->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) /* Find requested action mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) for (action_index = 0; action_index < num_actions; action_index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) action = synapse->actions_list[action_index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (sysfs_streq(buf, counter_synapse_action_str[action]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) /* If requested action mode not found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (action_index >= num_actions)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) err = counter->ops->action_set(counter, count, synapse, action_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) synapse->action = action_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) struct counter_action_avail_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) const enum counter_synapse_action *actions_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) size_t num_actions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) static ssize_t counter_synapse_action_available_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) const struct counter_action_avail_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) enum counter_synapse_action action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) ssize_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) for (i = 0; i < component->num_actions; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) action = component->actions_list[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) len += sprintf(buf + len, "%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) counter_synapse_action_str[action]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) static int counter_synapses_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) const struct counter_device *const counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) struct counter_count *const count, const char *const count_attr_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct counter_synapse *synapse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) const char *prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) struct counter_action_unit *action_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) struct counter_action_avail_unit *avail_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) /* Register each Synapse */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) for (i = 0; i < count->num_synapses; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) synapse = count->synapses + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) /* Generate attribute prefix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) prefix = kasprintf(GFP_KERNEL, "signal%d_",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) synapse->signal->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if (!prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) /* Allocate action attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) action_comp = kmalloc(sizeof(*action_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) if (!action_comp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) goto err_free_prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) action_comp->synapse = synapse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) action_comp->count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) /* Create action attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) parm.prefix = prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) parm.name = "action";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) parm.show = (counter->ops->action_get) ? counter_action_show : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) parm.store = (counter->ops->action_set) ? counter_action_store : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) parm.component = action_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) kfree(action_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) goto err_free_prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) /* Allocate action available attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) if (!avail_comp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) goto err_free_prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) avail_comp->actions_list = synapse->actions_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) avail_comp->num_actions = synapse->num_actions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) /* Create action_available attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) parm.prefix = prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) parm.name = "action_available";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) parm.show = counter_synapse_action_available_show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) parm.store = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) parm.component = avail_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) kfree(avail_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) goto err_free_prefix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) kfree(prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) err_free_prefix:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) kfree(prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) err_free_attr_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) struct counter_count_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) struct counter_count *count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) static ssize_t counter_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) const struct counter_count_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) struct counter_count *const count = component->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) err = counter->ops->count_read(counter, count, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return sprintf(buf, "%lu\n", val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) static ssize_t counter_count_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) const struct counter_count_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) struct counter_count *const count = component->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) err = kstrtoul(buf, 0, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) err = counter->ops->count_write(counter, count, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) static const char *const counter_count_function_str[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) [COUNTER_COUNT_FUNCTION_INCREASE] = "increase",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) [COUNTER_COUNT_FUNCTION_DECREASE] = "decrease",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) [COUNTER_COUNT_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) [COUNTER_COUNT_FUNCTION_QUADRATURE_X4] = "quadrature x4"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) static ssize_t counter_function_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) const struct counter_count_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) struct counter_count *const count = component->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) size_t func_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) enum counter_count_function function;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) err = counter->ops->function_get(counter, count, &func_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) count->function = func_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) function = count->functions_list[func_index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) return sprintf(buf, "%s\n", counter_count_function_str[function]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) static ssize_t counter_function_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) const struct counter_count_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) struct counter_count *const count = component->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) const size_t num_functions = count->num_functions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) size_t func_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) enum counter_count_function function;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) /* Find requested Count function mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) for (func_index = 0; func_index < num_functions; func_index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) function = count->functions_list[func_index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) if (sysfs_streq(buf, counter_count_function_str[function]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) /* Return error if requested Count function mode not found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (func_index >= num_functions)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) err = counter->ops->function_set(counter, count, func_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) count->function = func_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) struct counter_count_ext_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) struct counter_count *count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) const struct counter_count_ext *ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) static ssize_t counter_count_ext_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) const struct counter_count_ext_unit *const comp = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) const struct counter_count_ext *const ext = comp->ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) return ext->read(dev_get_drvdata(dev), comp->count, ext->priv, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) static ssize_t counter_count_ext_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) const struct counter_count_ext_unit *const comp = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) const struct counter_count_ext *const ext = comp->ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) return ext->write(dev_get_drvdata(dev), comp->count, ext->priv, buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) static int counter_count_ext_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) struct counter_count *const count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) const struct counter_count_ext *ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) struct counter_count_ext_unit *count_ext_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) /* Create an attribute for each extension */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) for (i = 0 ; i < count->num_ext; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) ext = count->ext + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) /* Allocate count_ext attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) count_ext_comp = kmalloc(sizeof(*count_ext_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (!count_ext_comp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) count_ext_comp->count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) count_ext_comp->ext = ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) /* Allocate count_ext attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) parm.name = ext->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) parm.show = (ext->read) ? counter_count_ext_show : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) parm.store = (ext->write) ? counter_count_ext_store : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) parm.component = count_ext_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) kfree(count_ext_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) err_free_attr_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) struct counter_func_avail_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) const enum counter_count_function *functions_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) size_t num_functions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) static ssize_t counter_count_function_available_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) const struct counter_func_avail_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) const enum counter_count_function *const func_list = component->functions_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) const size_t num_functions = component->num_functions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) enum counter_count_function function;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) ssize_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) for (i = 0; i < num_functions; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) function = func_list[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) len += sprintf(buf + len, "%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) counter_count_function_str[function]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) static int counter_count_attributes_create(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) const struct counter_device *const counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) struct counter_count *const count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) struct counter_count_unit *count_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) struct counter_count_unit *func_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) struct counter_func_avail_unit *avail_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) /* Allocate count attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) count_comp = kmalloc(sizeof(*count_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) if (!count_comp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) count_comp->count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) /* Create main Count attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) parm.name = "count";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) parm.show = (counter->ops->count_read) ? counter_count_show : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) parm.store = (counter->ops->count_write) ? counter_count_store : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) parm.component = count_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) kfree(count_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) /* Allocate function attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) func_comp = kmalloc(sizeof(*func_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) if (!func_comp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) func_comp->count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) /* Create Count function attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) parm.name = "function";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) parm.show = (counter->ops->function_get) ? counter_function_show : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) parm.store = (counter->ops->function_set) ? counter_function_store : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) parm.component = func_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) kfree(func_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) /* Allocate function available attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) if (!avail_comp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) avail_comp->functions_list = count->functions_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) avail_comp->num_functions = count->num_functions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) /* Create Count function_available attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) parm.name = "function_available";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) parm.show = counter_count_function_available_show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) parm.store = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) parm.component = avail_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) kfree(avail_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) /* Create Count name attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) err = counter_name_attribute_create(group, count->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) /* Register Count extension attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) err = counter_count_ext_register(group, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) err_free_attr_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) static int counter_counts_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) struct counter_device_attr_group *const groups_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) const struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) struct counter_count *count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) /* Register each Count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) for (i = 0; i < counter->num_counts; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) count = counter->counts + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) /* Generate Count attribute directory name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) name = kasprintf(GFP_KERNEL, "count%d", count->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) if (!name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) goto err_free_attr_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) groups_list[i].attr_group.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) /* Register the Synapses associated with each Count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) err = counter_synapses_register(groups_list + i, counter, count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) goto err_free_attr_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) /* Create all attributes associated with Count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) err = counter_count_attributes_create(groups_list + i, counter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) goto err_free_attr_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) err_free_attr_groups:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) kfree(groups_list[i].attr_group.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) counter_device_attr_list_free(&groups_list[i].attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) } while (i--);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) struct counter_size_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) size_t size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) static ssize_t counter_device_attr_size_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) const struct counter_size_unit *const comp = to_counter_attr(attr)->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) return sprintf(buf, "%zu\n", comp->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) static int counter_size_attribute_create(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) const size_t size, const char *const name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) struct counter_size_unit *size_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) /* Allocate size attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) size_comp = kmalloc(sizeof(*size_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) if (!size_comp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) size_comp->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) parm.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) parm.show = counter_device_attr_size_show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) parm.store = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) parm.component = size_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) goto err_free_size_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) err_free_size_comp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) kfree(size_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) struct counter_ext_unit {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) const struct counter_device_ext *ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) static ssize_t counter_device_ext_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) const struct counter_ext_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) const struct counter_device_ext *const ext = component->ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) return ext->read(dev_get_drvdata(dev), ext->priv, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) static ssize_t counter_device_ext_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) const struct counter_device_attr *const devattr = to_counter_attr(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) const struct counter_ext_unit *const component = devattr->component;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) const struct counter_device_ext *const ext = component->ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) return ext->write(dev_get_drvdata(dev), ext->priv, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) static int counter_device_ext_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) struct counter_ext_unit *ext_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) struct counter_attr_parm parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) /* Create an attribute for each extension */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) for (i = 0 ; i < counter->num_ext; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) /* Allocate extension attribute component */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) ext_comp = kmalloc(sizeof(*ext_comp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) if (!ext_comp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) ext_comp->ext = counter->ext + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) /* Allocate extension attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) parm.group = group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) parm.prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) parm.name = counter->ext[i].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) parm.show = (counter->ext[i].read) ? counter_device_ext_show : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) parm.store = (counter->ext[i].write) ? counter_device_ext_store : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) parm.component = ext_comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) err = counter_attribute_create(&parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) kfree(ext_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) err_free_attr_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) static int counter_global_attr_register(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) struct counter_device_attr_group *const group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) /* Create name attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) err = counter_name_attribute_create(group, counter->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) /* Create num_counts attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) err = counter_size_attribute_create(group, counter->num_counts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) "num_counts");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) /* Create num_signals attribute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) err = counter_size_attribute_create(group, counter->num_signals,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) "num_signals");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) /* Register Counter device extension attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) err = counter_device_ext_register(group, counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) goto err_free_attr_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) err_free_attr_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) static void counter_device_groups_list_free(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) struct counter_device_attr_group *const groups_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) const size_t num_groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) struct counter_device_attr_group *group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) /* loop through all attribute groups (signals, counts, global, etc.) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) for (i = 0; i < num_groups; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) group = groups_list + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) /* free all attribute group and associated attributes memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) kfree(group->attr_group.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) kfree(group->attr_group.attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) counter_device_attr_list_free(&group->attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) kfree(groups_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) static int counter_device_groups_list_prepare(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) const size_t total_num_groups =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) counter->num_signals + counter->num_counts + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) struct counter_device_attr_group *groups_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) size_t num_groups = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) /* Allocate space for attribute groups (signals, counts, and ext) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) groups_list = kcalloc(total_num_groups, sizeof(*groups_list),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) if (!groups_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) /* Initialize attribute lists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) for (i = 0; i < total_num_groups; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) INIT_LIST_HEAD(&groups_list[i].attr_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) /* Register Signals */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) err = counter_signals_register(groups_list, counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) goto err_free_groups_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) num_groups += counter->num_signals;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) /* Register Counts and respective Synapses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) err = counter_counts_register(groups_list + num_groups, counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) goto err_free_groups_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) num_groups += counter->num_counts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) /* Register Counter global attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) err = counter_global_attr_register(groups_list + num_groups, counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) goto err_free_groups_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) num_groups++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) /* Store groups_list in device_state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) counter->device_state->groups_list = groups_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) counter->device_state->num_groups = num_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) err_free_groups_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) counter_device_groups_list_free(groups_list, num_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) static int counter_device_groups_prepare(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) struct counter_device_state *const device_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) size_t i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) struct counter_device_attr_group *group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) struct counter_device_attr *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) /* Allocate attribute groups for association with device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) device_state->groups = kcalloc(device_state->num_groups + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) sizeof(*device_state->groups),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) if (!device_state->groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) /* Prepare each group of attributes for association */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) for (i = 0; i < device_state->num_groups; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) group = device_state->groups_list + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) /* Allocate space for attribute pointers in attribute group */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) group->attr_group.attrs = kcalloc(group->num_attr + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) sizeof(*group->attr_group.attrs), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) if (!group->attr_group.attrs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) goto err_free_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) /* Add attribute pointers to attribute group */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) j = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) list_for_each_entry(p, &group->attr_list, l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) group->attr_group.attrs[j++] = &p->dev_attr.attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) /* Group attributes in attribute group */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) device_state->groups[i] = &group->attr_group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) /* Associate attributes with device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) device_state->dev.groups = device_state->groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) err_free_groups:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) group = device_state->groups_list + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) kfree(group->attr_group.attrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) group->attr_group.attrs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) } while (i--);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) kfree(device_state->groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) /* Provides a unique ID for each counter device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) static DEFINE_IDA(counter_ida);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) static void counter_device_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) struct counter_device *const counter = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) struct counter_device_state *const device_state = counter->device_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) kfree(device_state->groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) counter_device_groups_list_free(device_state->groups_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) device_state->num_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) ida_simple_remove(&counter_ida, device_state->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) kfree(device_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) static struct device_type counter_device_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) .name = "counter_device",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) .release = counter_device_release
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) static struct bus_type counter_bus_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) .name = "counter"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) * counter_register - register Counter to the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) * @counter: pointer to Counter to register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) * This function registers a Counter to the system. A sysfs "counter" directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) * will be created and populated with sysfs attributes correlating with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) * Counter Signals, Synapses, and Counts respectively.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) int counter_register(struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) struct counter_device_state *device_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) /* Allocate internal state container for Counter device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) device_state = kzalloc(sizeof(*device_state), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) if (!device_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) counter->device_state = device_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) /* Acquire unique ID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) device_state->id = ida_simple_get(&counter_ida, 0, 0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) if (device_state->id < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) err = device_state->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) goto err_free_device_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) /* Configure device structure for Counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) device_state->dev.type = &counter_device_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) device_state->dev.bus = &counter_bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) if (counter->parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) device_state->dev.parent = counter->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) device_state->dev.of_node = counter->parent->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) dev_set_name(&device_state->dev, "counter%d", device_state->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) device_initialize(&device_state->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) dev_set_drvdata(&device_state->dev, counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) /* Prepare device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) err = counter_device_groups_list_prepare(counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) goto err_free_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) /* Organize device attributes to groups and match to device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) err = counter_device_groups_prepare(device_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) goto err_free_groups_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) /* Add device to system */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) err = device_add(&device_state->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) goto err_free_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) err_free_groups:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) kfree(device_state->groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) err_free_groups_list:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) counter_device_groups_list_free(device_state->groups_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) device_state->num_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) err_free_id:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) ida_simple_remove(&counter_ida, device_state->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) err_free_device_state:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) kfree(device_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) EXPORT_SYMBOL_GPL(counter_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) * counter_unregister - unregister Counter from the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) * @counter: pointer to Counter to unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) * The Counter is unregistered from the system; all allocated memory is freed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) void counter_unregister(struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) if (counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) device_del(&counter->device_state->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) EXPORT_SYMBOL_GPL(counter_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) static void devm_counter_unreg(struct device *dev, void *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) counter_unregister(*(struct counter_device **)res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) * devm_counter_register - Resource-managed counter_register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) * @dev: device to allocate counter_device for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) * @counter: pointer to Counter to register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) * Managed counter_register. The Counter registered with this function is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) * automatically unregistered on driver detach. This function calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) * counter_register internally. Refer to that function for more information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) * If an Counter registered with this function needs to be unregistered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) * separately, devm_counter_unregister must be used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) * RETURNS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) * 0 on success, negative error number on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) int devm_counter_register(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) struct counter_device **ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) ptr = devres_alloc(devm_counter_unreg, sizeof(*ptr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) if (!ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) ret = counter_register(counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) *ptr = counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) devres_add(dev, ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) devres_free(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) EXPORT_SYMBOL_GPL(devm_counter_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) static int devm_counter_match(struct device *dev, void *res, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) struct counter_device **r = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) if (!r || !*r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) WARN_ON(!r || !*r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) return *r == data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) * devm_counter_unregister - Resource-managed counter_unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) * @dev: device this counter_device belongs to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) * @counter: pointer to Counter associated with the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) * Unregister Counter registered with devm_counter_register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) void devm_counter_unregister(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) struct counter_device *const counter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) rc = devres_release(dev, devm_counter_unreg, devm_counter_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) counter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) WARN_ON(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) EXPORT_SYMBOL_GPL(devm_counter_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) static int __init counter_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) return bus_register(&counter_bus_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) static void __exit counter_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) bus_unregister(&counter_bus_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) subsys_initcall(counter_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) module_exit(counter_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) MODULE_DESCRIPTION("Generic Counter interface");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) MODULE_LICENSE("GPL v2");