read_proc的用法实例

说明

本测试程序主要参考了《linux设备驱动程序》第三版的第四章“调试技术”的‘/proc文件’一节。

并对一些关键函数进行了实例化。


以下是mod1.c

#include<linux/init.h>

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/proc_fs.h>   /* read_proc需要的头文件。 */

MODULE_LICENSE("GPL");
/*
    原型函数:int (*read_proc)(char *page, char **start, off_t offset, int count, int *eof, void *data)
    这个函数与read的系统调用函数功能类似。就在/proc中为驱动程序设计了一个特有了文件(假设名scull)后,则用户使用cat /proc/scull时,会调用到此函数。
    在/proc中创建文件,并且完成此文件与一个read_proc的关联关系的函数是create_proc_read_entry.
    删除这种关系,并且删除这个文件的函数是remove_proc_entry.
    实体函数:scull_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data)
parameter:
    buf:是从驱动层向应用层返回的数据区;当有用户读此/proc/xxx的文件时,由系统分配一页的缓存区,驱动使用read_proc此写入数据。
    start: 表示写在此页的哪里,此用法复杂,如果是返回小量数据(不超过一页)赋值为NULL。
    offset:与read用法一致,表示文件指针的偏移。
    count:与read用法一致,表示要读多少个字节。
    eof:  输出参数。
    data:由驱动内部使用。
return:
    返回值是可读到的字节数。
*/
int scull_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
    int len = 0;
    
    len += sprintf(buf + len, "I am peter\r\n and thank you\r\n");
    *eof = 1;
    return len;
}

static int func1(void)
{
        printk("In Func: %s...\n",__func__);
        
        return 0;
}

EXPORT_SYMBOL(func1);

static int __init hello_init(void)
{
/* 当你定义了read_proc函数,你就需要将它连接到/proc目录中的某个条目。这个工作可以借助一个叫做create_proc_read_entry的函数完成
struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void *data)
参数:
name是要创建的/proc文件名,
mode是文件的保护掩码(0为系统缺省值),
base指明创建文件的目录(如果设置为NULL,文件就创建在/proc根目录下),
read_proc是read_proc函数的入口地址,
data被内核忽略(但会被传递给read_proc函数)。
*/
    create_proc_read_entry("scullmem",
        0 /* default mode */,
        NULL /* parent dir */,
        scull_read_procmem,
        NULL /* client data */);
        
        printk("Module 1,Init!\n");
        return 0;
}

static void __exit hello_exit(void)
{
    remove_proc_entry("scullmem", NULL /* parent dir */);
    printk("Module 1,Exit!\n");
}

module_init(hello_init);
module_exit(hello_exit);




  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
下面是一个使用`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`需要更多的代码和配置。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值