使用proc函数的实例

这个例子使用了内核模块,在/proc目录下创建一个名叫procfs_example的目录,并且在该目录下创建三个普通文件和一个软连接。一个文件名 叫foo,只读,内容为foo = 'foo';一个文件名叫bar只读,内容为bar = 'bar';一个叫jiffies,只读,它会动态地显示jiffies的值。软连接名叫jiffies_too,它是对文件jiffies的软连接。
以下是实验内容:
lzel@lzel-desktop:~/works/proc$ ls
Makefile  procfs_example.c
lzel@lzel-desktop:~/works/proc$ cat procfs_example.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>

#define MODULE_VERS "1.0"
#define MODULE_NAME "procfs_example"
#define FOOBAR_LEN 8

struct fb_data_t {
        char name[FOOBAR_LEN+1];
        char value[FOOBAR_LEN+1];
};
static struct proc_dir_entry *example_dir,*foo_file,*bar_file,*jiffies_file,*symlink;
struct fb_data_t foo_data,bar_data;

static int proc_read_jiffies (char *page,char **stat,off_t off,int count,int *eof,void *data)
{
        int len;

        len = sprintf(page,"jiffies = %ld/n",jiffies);
        return len;
}
static int proc_read_foobar(char *page,char **stat,off_t off,int count,int *eof,void *data)
{
        int len;
        struct fb_data_t *fb_data = (struct fb_data_t*)data;
        len = sprintf(page,"%s = '%s'/n",fb_data->name,fb_data->value);
        return len;
}

static int proc_write_foobar (struct file *file,const char *buffer,unsigned long count,void *data)
{
        int len;
        struct fb_data_t *fb_data = (struct fb_data_t *)data;
    if (count > FOOBAR_LEN)
        len = FOOBAR_LEN;
    else
        len = count;
    if (copy_from_user(fb_data->value,buffer,len))
        return -EFAULT;
    fb_data->value[len] = '/n';
    return len;
}
static int __init init_procfs_example (void)
{
    int rv = 0;

    example_dir = proc_mkdir (MODULE_NAME,NULL);
    if (example_dir == NULL)
    {
        rv = -ENOMEM;
        goto out;
    }
    example_dir->owner = THIS_MODULE;
    jiffies_file = create_proc_read_entry ("jiffies",0444,example_dir,proc_read_jiffies,NULL);
    if (jiffies_file == NULL)
    {
        rv = -ENOMEM;
        goto no_jiffies;
    }
    jiffies_file->owner = THIS_MODULE;
    foo_file = create_proc_entry ("foo",0644,example_dir);
    if (foo_file == NULL)
    {
        rv = -ENOMEM;
        goto no_foo;
    }
    strcpy(foo_data.name,"foo");
    strcpy(foo_data.value,"foo");
    foo_file->data = &foo_data;
    foo_file->read_proc = proc_read_foobar;
    foo_file->write_proc = proc_write_foobar;
    foo_file->owner = THIS_MODULE;

    bar_file = create_proc_entry ("bar",0644,example_dir);
    if (bar_file == NULL)
    {
        rv = -ENOMEM;
        goto no_bar;
    }
    strcpy(bar_data.name,"bar");
    strcpy(bar_data.value,"bar");
    bar_file->data = &bar_data;
    bar_file->read_proc = proc_read_foobar;
    bar_file->write_proc = proc_write_foobar;
 bar_file->owner = THIS_MODULE;

    symlink = proc_symlink ("jiffies_too",example_dir,"jiffies");
    if (symlink == NULL)
    {
        rv = -ENOMEM;
        goto no_symlink;
    }
    symlink->owner = THIS_MODULE;

    printk(KERN_INFO"%s %s initialised/n",MODULE_NAME,MODULE_VERS);
    return 0;
    no_symlink:
        remove_proc_entry("bar",example_dir);
    no_bar:
        remove_proc_entry ("foo",example_dir);
    no_foo:
        remove_proc_entry ("jiffies",example_dir);
    no_jiffies:
        remove_proc_entry (MODULE_NAME,NULL);
    out:
        return rv;
}
static void __exit cleanup_procfs_example (void)
{
    remove_proc_entry("jiffies_too",example_dir);
    remove_proc_entry("bar",example_dir);
    remove_proc_entry("foo",example_dir);
    remove_proc_entry("jiffies",example_dir);
    remove_proc_entry(MODULE_NAME,NULL);

    printk(KERN_INFO"%s %s removed/n",MODULE_NAME,MODULE_VERS);
}
module_init(init_procfs_example);
module_exit(cleanup_procfs_example);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("lzel");
MODULE_DESCRIPTION("procfs examples");

lzel@lzel-desktop:~/works/proc$ cat Makefile
TARGET=procfs_example
KERNEL=`uname -r`
#KDIR = /usr/src/linux-headers-$(KERNEL)
KDIR = /usr/src/kernels/2.6.18-194.el5-i686/
PWD = `pwd`
obj-m:=$(TARGET).o
default:
        make -C $(KDIR) M=$(PWD) modules
clean:
        make -C $(KDIR) M=$(PWD) clean
lzel@lzel-desktop:~/works/proc$ sudo make
[sudo] password for lzel:
make -C /usr/src/linux-headers-`uname -r` M=`pwd` modules
make[1]: 正在进入目录 `/usr/src/linux-headers-2.6.24-21-generic'
  CC [M]  /home/lzel/works/proc/procfs_example.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/lzel/works/proc/procfs_example.mod.o
  LD [M]  /home/lzel/works/proc/procfs_example.ko
make[1]:正在离开目录 `/usr/src/linux-headers-2.6.24-21-generic'
lzel@lzel-desktop:~/works/proc$ ls
procfs_example.c   procfs_example.ko     procfs_example.mod.o  procfs_example.o
Makefile  Module.symvers   procfs_example.mod.c       
lzel@lzel-desktop:~/works/proc$ sudo insmod procfs_example.ko
lzel@lzel-desktop:~/works/proc$ lsmod |head
Module                  Size  Used by
procfs_example          4024  0
ipv6                  267780  10
af_packet              23812  2
rfcomm                 41744  2
l2cap                  25728  13 rfcomm
bluetooth              61156  4 rfcomm,l2cap
ppdev                  10372  0
cpufreq_conservative     8712  0
cpufreq_ondemand        9740  0
lzel@lzel-desktop:~/works/proc$ dmesg |tail
[   72.183969] Bluetooth: RFCOMM socket layer initialized
[   72.184566] Bluetooth: RFCOMM TTY layer initialized
[   72.184593] Bluetooth: RFCOMM ver 1.8
[   75.149946] NET: Registered protocol family 17
[   83.211043] NET: Registered protocol family 10
[   83.222138] lo: Disabled Privacy Extensions
[   94.443153] eth1: no IPv6 routers present
[ 4620.210470] procfs_example 1.0 initialised //初始化完成
lzel@lzel-desktop:~/works/proc$
现在到/proc中去看看,是不是如我们所设想的一样呢。
lzel@lzel-desktop:~/works/proc$ ls /proc/|grep procfs_example
procfs_example //果然有procfs_example目录,这样就让我们进入到这个目录去验证其他的文件
lzel@lzel-desktop:~/works/proc$ cd /proc/procfs_example/
lzel@lzel-desktop:/proc/procfs_example$ ll //确实有三个普通文件和一个软连接
总用量 0
-rw-r--r-- 1 root root 0 2008-10-11 20:23 bar
-rw-r--r-- 1 root root 0 2008-10-11 20:23 foo
-r--r--r-- 1 root root 0 2008-10-11 20:23 jiffies
lrwxrwxrwx 1 root root 7 2008-10-11 20:23 jiffies_too -&gt; jiffies
lzel@lzel-desktop:/proc/procfs_example$ cat bar //查看bar
bar = 'bar'
lzel@lzel-desktop:/proc/procfs_example$ cat foo //查看foo
foo = 'foo'
lzel@lzel-desktop:/proc/procfs_example$ cat jiffies //查看jiffies
jiffies = 1153731
lzel@lzel-desktop:/proc/procfs_example$ cat jiffies_too //查看软连接
jiffies = 1158238
lzel@lzel-desktop:/proc/procfs_example$
细 心的读者也许看到了,两个jiffies的值是不同的。因为 jiffies是内核中的一个全局变量,用来记录自系统启动以来产生的节拍数。它自从开机以来就一刻不停的增长着。所以可以用 jiffies/tick_rate 来计算计算运行了多长时间。jiffies定义在文件<linux/jiffies.h>中:

extern unsigned long volatile jiffies;

我们可以用一下命令动态地查看jiffies的变化情况:
lzel@lzel-desktop:/proc/procfs_example$ watch cat jiffies
或者
lzel@lzel-desktop:/proc/procfs_example$ watch cat jiffies_too
两者一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用`regmap I2C_SMBUS_BLOCK_PROC_CALL`函数实例: ```c #include <linux/i2c.h> #include <linux/regmap.h> /* 假设我们已经获取了一个i2c_client结构体指针,称为client */ /* 定义一个块读处理函数 */ static int my_i2c_block_read(struct i2c_client *client, u8 reg, u8 *val, u16 len) { struct i2c_msg msg[2]; int ret; /* 发送写命令,以设置寄存器地址 */ msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = ® /* 发送读命令,以获取数据 */ msg[1].addr = client->addr; msg[1].flags = I2C_M_RD | I2C_M_RECV_LEN; msg[1].len = len; msg[1].buf = val; /* 发送I2C消息,执行块读操作 */ ret = i2c_transfer(client->adapter, msg, 2); if (ret == 2) ret = 0; else ret = (ret < 0) ? ret : -EIO; return ret; } /* 定义一个块写处理函数 */ static int my_i2c_block_write(struct i2c_client *client, u8 reg, u8 *val, u16 len) { struct i2c_msg msg; u8 *buf; int ret; /* 分配一个缓冲区,用于组装要发送的数据 */ buf = kmalloc(len + 1, GFP_KERNEL); if (!buf) return -ENOMEM; /* 将寄存器地址和数据组装到缓冲区中 */ buf[0] = reg; memcpy(&buf[1], val, len); /* 发送I2C消息,执行块写操作 */ msg.addr = client->addr; msg.flags = 0; msg.len = len + 1; msg.buf = buf; ret = i2c_transfer(client->adapter, &msg, 1); if (ret == 1) ret = 0; else ret = (ret < 0) ? ret : -EIO; kfree(buf); return ret; } /* 定义一个regmap_config结构体 */ static const struct regmap_config my_regmap_config = { .name = "my_regmap", .reg_bits = 8, .val_bits = 8, .max_register = 0xff, .write = my_i2c_block_write, .read = my_i2c_block_read, .cache_type = REGCACHE_NONE, }; /* 初始化一个regmap结构体 */ static struct regmap *my_regmap_init(struct i2c_client *client) { struct regmap *map; /* 分配一个regmap结构体 */ map = devm_regmap_init_i2c(client, &my_regmap_config); if (IS_ERR(map)) { pr_err("Failed to allocate regmap: %ld\n", PTR_ERR(map)); return NULL; } return map; } /* 在驱动程序中使用regmap */ static int my_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct regmap *map; /* 初始化一个regmap结构体 */ map = my_regmap_init(client); if (!map) return -ENODEV; /* 使用regmap进行读写操作 */ regmap_write(map, 0x10, 0x55); regmap_read(map, 0x20, &val); return 0; } /* 在驱动程序中使用regmap */ static int my_driver_remove(struct i2c_client *client) { /* 在驱动程序卸载时,释放regmap结构体 */ regmap_exit(dev_get_regmap(client, NULL)); return 0; } /* 定义一个i2c_driver结构体 */ static const struct i2c_device_id my_driver_id[] = { { "my_device", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, my_driver_id); static struct i2c_driver my_driver = { .driver = { .name = "my_driver", }, .probe = my_driver_probe, .remove = my_driver_remove, .id_table = my_driver_id, }; /* 注册i2c_driver */ module_i2c_driver(my_driver); ``` 在上面的代码中,我们定义了两个块处理函数`my_i2c_block_read`和`my_i2c_block_write`,用于在I2C设备上执行块读写操作。然后,我们定义了一个`regmap_config`结构体,在其中指定了`write`和`read`函数为上述定义的块处理函数。接着,我们使用`devm_regmap_init_i2c`函数初始化了一个`regmap`结构体,并在驱动程序中使用`regmap_write`和`regmap_read`函数来进行寄存器读写操作。 注意:这只是一个简单的示例,实际上使用`regmap`需要更多的代码和配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值