// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) Intel Corporation * Author: Shao Guohua */ #include #include #include #include #include #include "datapath.h" #undef local_dbg #define local_dbg(fmt, arg...) pr_debug(fmt, ##arg) static void *dp_seq_start(struct seq_file *s, loff_t *pos) { struct dp_proc_file_entry *p = s->private; if (p->pos < 0) return NULL; return p; } static void *dp_seq_next(struct seq_file *s, void *v, loff_t *pos) { struct dp_proc_file_entry *p = s->private; *pos = p->pos; if (p->pos >= 0) return p; else return NULL; } static void dp_seq_stop(struct seq_file *s, void *v) { } static int dp_seq_show(struct seq_file *s, void *v) { struct dp_proc_file_entry *p = s->private; int pos; if (p->pos >= 0) { if (p->multi_callback) { local_dbg("multiple call"); pos = p->multi_callback(s, p->pos); } else if (p->single_callback) { local_dbg("single call: %px", p->single_callback); p->single_callback(s); pos = -1; } if (!seq_has_overflowed(s)) p->pos = pos; } return 0; } static const struct seq_operations dp_seq_ops = { .start = dp_seq_start, .next = dp_seq_next, .stop = dp_seq_stop, .show = dp_seq_show }; void dummy_single_show(struct seq_file *s) { seq_puts(s, "Cat Not implemented yet !\n"); } static int dp_proc_open(struct inode *inode, struct file *file) { struct seq_file *s; struct dp_proc_file_entry *p; struct dp_proc_entry *entry; int ret; ret = seq_open(file, &dp_seq_ops); if (ret) return ret; s = file->private_data; p = devm_kzalloc(&g_dp_dev->dev, sizeof(*p), GFP_ATOMIC); if (!p) { (void)seq_release(inode, file); return -ENOMEM; } memset(p, 0, sizeof(*p)); entry = inode->i_private; if (entry->multi_callback) p->multi_callback = entry->multi_callback; if (entry->single_callback) p->single_callback = entry->single_callback; else p->single_callback = dummy_single_show; if (entry->init_callback) p->pos = entry->init_callback(); else p->pos = 0; s->private = p; return 0; } static int dp_proc_release(struct inode *inode, struct file *file) { struct seq_file *s; s = file->private_data; devm_kfree(&g_dp_dev->dev, s->private); return seq_release(inode, file); } static int dp_seq_single_show(struct seq_file *s, void *v) { struct dp_proc_entry *p = s->private; p->single_callback(s); return 0; } static int dp_proc_single_open(struct inode *inode, struct file *file) { return single_open(file, dp_seq_single_show, inode->i_private); } #define MEM_ZERO(x, y) memset(&(x), 0, y) void dp_proc_entry_create(struct dentry *parent_node, struct dp_proc_entry *proc_entry) { struct dentry *file; if (!proc_entry || !proc_entry->name) return; MEM_ZERO(proc_entry->ops, sizeof(proc_entry->ops)); proc_entry->ops.owner = THIS_MODULE; if (proc_entry->single_callback) { proc_entry->ops.open = dp_proc_single_open; proc_entry->ops.release = single_release; } else if (proc_entry->multi_callback) { proc_entry->ops.open = dp_proc_open; proc_entry->ops.release = dp_proc_release; } else { /*regard as single call with dummy show*/ proc_entry->ops.open = dp_proc_single_open; proc_entry->ops.release = single_release; proc_entry->single_callback = dummy_single_show; } proc_entry->ops.read = seq_read; proc_entry->ops.llseek = seq_lseek; proc_entry->ops.write = proc_entry->write_callback; /*Don't know why checkpatch propose to use 0444 *Instead of S_IRUGO ??? */ file = debugfs_create_file(proc_entry->name, 0644 /*(S_IFREG | 0444)*/, parent_node, proc_entry, &proc_entry->ops); } EXPORT_SYMBOL(dp_proc_entry_create);