// SPDX-License-Identifier: GPL-2.0
/*
* Generic Counter interface
* Copyright (C) 2018 William Breathitt Gray
*/
#include <linux/counter.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/idr.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/types.h>
const char *const counter_count_direction_str[2] = {
[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
};
EXPORT_SYMBOL_GPL(counter_count_direction_str);
const char *const counter_count_mode_str[4] = {
[COUNTER_COUNT_MODE_NORMAL] = "normal",
[COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
[COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
};
EXPORT_SYMBOL_GPL(counter_count_mode_str);
ssize_t counter_signal_enum_read(struct counter_device *counter,
struct counter_signal *signal, void *priv,
char *buf)
{
const struct counter_signal_enum_ext *const e = priv;
int err;
size_t index;
if (!e->get)
return -EINVAL;
err = e->get(counter, signal, &index);
if (err)
return err;
if (index >= e->num_items)
return -EINVAL;
return sprintf(buf, "%s\n", e->items[index]);
}
EXPORT_SYMBOL_GPL(counter_signal_enum_read);
ssize_t counter_signal_enum_write(struct counter_device *counter,
struct counter_signal *signal, void *priv,
const char *buf, size_t len)
{
const struct counter_signal_enum_ext *const e = priv;
ssize_t index;
int err;
if (!e->set)
return -EINVAL;
index = __sysfs_match_string(e->items, e->num_items, buf);
if (index < 0)
return index;
err = e->set(counter, signal, index);
if (err)
return err;
return len;
}
EXPORT_SYMBOL_GPL(counter_signal_enum_write);
ssize_t counter_signal_enum_available_read(struct counter_device *counter,
struct counter_signal *signal,
void *priv, char *buf)
{
const struct counter_signal_enum_ext *const e = priv;
size_t i;
size_t len = 0;
if (!e->num_items)
return 0;
for (i = 0; i < e->num_items; i++)
len += sprintf(buf + len, "%s\n", e->items[i]);
return len;
}
EXPORT_SYMBOL_GPL(counter_signal_enum_available_read);
ssize_t counter_count_enum_read(struct counter_device *counter,
struct counter_count *count, void *priv,
char *buf)
{
const struct counter_count_enum_ext *const e = priv;
int err;
size_t index;
if (!e->get)
return -EINVAL;
err = e->get(counter, count, &index);
if (err)
return err;
if (index >= e->num_items)
return -EINVAL;
return sprintf(buf, "%s\n", e->items[index]);
}
EXPORT_SYMBOL_GPL(counter_count_enum_read);
ssize_t counter_count_enum_write(struct counter_device *counter,
struct counter_count *count, void *priv,
const char *buf, size_t len)
{
const struct counter_count_enum_ext *const e = priv;
ssize_t index;
int err;
if (!e->set)
return -EINVAL;
index = __sysfs_match_string(e->items, e->num_items, buf);
if (index < 0)
return index;
err = e->set(counter, count, index);
if (err)
return err;
return len;
}
EXPORT_SYMBOL_GPL(counter_count_enum_write);
ssize_t counter_count_enum_available_read(struct counter_device *counter,
struct counter_count *count,
void *priv, char *buf)
{
const struct counter_count_enum_ext *const e = priv;
size_t i;
size_t len = 0;
if (!e->num_items)
return 0;
for (i = 0; i < e->num_items; i++)
len += sprintf(buf + len, "%s\n", e->items[i]);
return len;
}
EXPORT_SYMBOL_GPL(counter_count_enum_available_read);
ssize_t counter_device_enum_read(struct counter_device *counter, void *priv,
char *buf)
{
const struct counter_device_enum_ext *const e = priv;
int err;
size_t index;
if (!e->get)
return -EINVAL;
err = e->get(counter, &index);
if (err)
return err;
if (index >= e->num_items)
return -EINVAL;
return sprintf(buf, "%s\n", e->items[index]);
}
EXPORT_SYMBOL_GPL(counter_device_enum_read);
ssize_t counter_device_enum_write(struct counter_device *counter, void *priv,
const char *buf, size_t len)
{
const struct counter_device_enum_ext *const e = priv;
ssize_t index;
int err;
if (!e->set)
return -EINVAL;
index = __sysfs_match_string(e->items, e->num_items, buf);
if (index < 0)
return index;
err = e->set(counter, index);
if (err)
return err;
return len;
}
EXPORT_SYMBOL_GPL(counter_device_enum_write);
ssize_t counter_device_enum_available_read(struct counter_device *counter,
void *priv, char *buf)
{
const struct counter_device_enum_ext *const e = priv;
size_t i;
size_t len = 0;
if (!e->num_items)
return 0;
for (i = 0; i < e->num_items; i++)
len += sprintf(buf + len, "%s\n", e->items[i]);
return len;
}
EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
static const char *const counter_signal_level_str[] = {
[COUNTER_SIGNAL_LEVEL_LOW] = "low",
[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
};
/**
* counter_signal_read_value_set - set counter_signal_read_value data
* @val: counter_signal_read_value structure to set
* @type: property Signal data represents
* @data: Signal data
*
* This function sets an opaque counter_signal_read_value structure with the
* provided Signal data.
*/
void counter_signal_read_value_set(struct counter_signal_read_value *const val,
const enum counter_signal_value_type type,
void *const data)
{
if (type == COUNTER_SIGNAL_LEVEL)
val->len = sprintf(val->buf, "%s\n",
counter_signal_level_str[*(enum counter_signal_level *)data]);
else
val->len = 0;
}
EXPORT_SYMBOL_GPL(counter_signal_read_value_set);
/**
* counter_count_read_value_set - set counter_count_read_value data
* @val: counter_count_read_value structure to set
* @type: property Count data represents
* @data: Count data
*
* This function sets an opaque counter_count_read_value structur
|