#include <linux/module.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/fs.h> #include <linux/kernel.h> /* printk() */ #include <asm/uaccess.h> /* copy_*_user */
#define PROC_NAME "myproc"
static int proc_open(struct inode *inodp, struct file *filp); static ssize_t proc_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos);
static struct file_operations proc_fops = { .owner = THIS_MODULE, .open = proc_open, .read = seq_read, .write = proc_write, .llseek = seq_lseek, .release = seq_release, };
//only for test
static ssize_t proc_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) { size_t copied = 0; int i; char *kbuf; kbuf = kmalloc(size, GFP_KERNEL); if (!kbuf) goto out; if (copy_from_user(kbuf, buf, size)) goto out_cp;
copied = size; *ppos += size;
//
for(i = 0; i < size; i++) printk("%c", kbuf[i]); if (kbuf[0] == '1') { printk("open\n"); } else if (kbuf[0] == '0') { printk("close\n"); } else { printk("error\n"); } //
out_cp: kfree(kbuf); out: return copied; }
//sfile 参数可以几乎是一直被忽略. pos 是一个整型位置值, 指示应当从哪里读. 位置的解释完全取决于实现; 在结果文件里不需要是一个字节位置. 因为 seq_file 实现典型地步进一系列感兴趣的项, position 常常被解释为指向序列中下一个项的指针. scull 驱动解释每个设备作为系列中的一项, 因此进入的 pos 简单地是一个 scull_device 数组的索引. 因此, scull 使用的 start 方法是:
void * seq_start(struct seq_file *m, loff_t *pos) { loff_t *item;
printk("seq_start %ld\n", *pos); item = kmalloc(sizeof(loff_t), GFP_KERNEL); if (!item) { printk("kmalloc err\n"); goto err; }
*item = *pos; err: return item; }
void seq_stop(struct seq_file *m, void *v) { kfree(v); }
//这里, v 是从前一个对 start 或者 next 的调用返回的 iterator, pos 是文件的当前位置. next 应当递增有 pos 指向的值; 根据你的 iterator 是如何工作的, 你可能(尽管可能不会)需要递增 pos 不止是 1. 这是 scull 所做的:
void * seq_next(struct seq_file *m, void *v, loff_t *pos) { loff_t *item = (loff_t *) v; *pos = ++(*item);
return item; }
int seq_show(struct seq_file *m, void *v) { loff_t *item = (loff_t *) v;
seq_printf(m, "%Ld\n", *item);
return 0; }
static struct seq_operations seq_ops = { .start = seq_start, .stop = seq_stop, .next = seq_next, .show = seq_show, };
static int proc_open(struct inode *inodp, struct file *filp) { printk("proc_open %\n"); return seq_open(filp, &seq_ops); }
static int __init proc_init(void) { struct proc_dir_entry *entry;
entry = create_proc_entry(PROC_NAME, 0, NULL); if (!entry) printk(KERN_ALERT "create failure.\n");
entry->proc_fops = &proc_fops;
return 0; }
static void __exit proc_exit(void) { remove_proc_entry(PROC_NAME, NULL); }
MODULE_LICENSE("GPL");
module_init(proc_init); module_exit(proc_exit);
|