一、编程要求
-
在内[[核中不支持浮点类型打印
-
将si7006硬件数据读取到内核空间,拷贝到用户空间
-
在i2c子系统驱动中,需要编写读取温湿度传感器函数
-
在probe函数中
- 注册字符设备驱动(分步注册)
- 自动创建设备节点
-
通过ioctl函数判断应用层发送命令码,是读取温度的数据还是湿度的数据
-
编写应用层程序 公式
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/device.h>struct i2c_client *gclient;
unsigned int major = 0;
#define CNAME "myled"
struct class *cls;
struct device *device;int myled_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",FILE,func,LINE);
return 0;
}ssize_t myled_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
printk("%s:%s:%d\n",FILE,func,LINE);
return 0;
}ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
printk("%s:%s:%d\n",FILE,func,LINE);
return 0;
}int myled_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",FILE,func,LINE);
return 0;
}//操作方法结构体
const struct file_operations fops = {
.open = myled_open,
.read = myled_read,
.write = myled_write,
.release = myled_close,
};//函数功能:读取电子串号和固件版本号的函数
int read_serial_firmware(unsigned short reg)
{
char r_buf[] = {(reg >> 8 & 0xff),reg & 0xff};
char value;
int num;
struct i2c_msg r_msg[2] = {
[0] = {
.addr = gclient->addr, //从机地址
.flags = 0, //写标志位
.len = 2, //消息长度
.buf = r_buf, //从reg寄存器中读取数据
},
[1] = {
.addr = gclient->addr, //从机地址
.flags = 1,//读标志位
.len = 1, //消息长度
.buf = &value, //读取到的数据内容
},
};
//发送数据
num = i2c_transfer(gclient->adapter,r_msg,ARRAY_SIZE(r_msg));
if(num != ARRAY_SIZE(r_msg))
{
printk("i2c transfer is error\n");
return -EIO;
}
return value;
}//当设备驱动层和总线驱动层匹配成功执行probe函数
int si7006_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
gclient = client;
printk("%s:%s:%d\n",FILE,func,LINE);
//读取电子串号
ret = read_serial_firmware(0xFCC9);
printk("serial(0x06) = %#x\n",ret);
//读取固件版本号
ret = read_serial_firmware(0x84B8);
printk("fireware(0xff/0x20) = %#x\n",ret);//读取温湿度传感器协议版本号 ret = read_serial_firmware(0xE340); printk("temperature(0xff/0x20) = %#x\n",ret); ret = read_serial_firmware(0xE540); printk("Relative Humidity(0xff/0x20) = %#x\n",ret); //注册字符设备驱动 major = register_chrdev(0,CNAME,&fops); if(major < 0){ printk("register chrdev is error\n"); return -EIO; } //向上层提交目录信息 cls = class_create(THIS_MODULE,CNAME); if(IS_ERR(cls)){ return PTR_ERR(cls); } //向上层提交设备节点信息 device = device_create(cls,NULL,MKDEV(major,0),NULL,CNAME); if(IS_ERR(device)){ return PTR_ERR(device); } printk("major = %d\n",major);//打印主设备号的值 //判断读取的是温度还是湿度的数据,此处不会 if(gclient->flags==1 && gclient->flags) { ; } return 0;
}
//当任意一方卸载,执行remove函数
int si7006_remove(struct i2c_client *client)
{
//注销字符设备驱动
unregister_chrdev(major,CNAME);
printk("%s:%s:%d\n",FILE,func,LINE);
return 0;
}const struct of_device_id si7006_tabble[] = {
{.compatible = "hqyj,si7006",},
{},//防止数组越界
};//初始化i2c_driver结构体
struct i2c_driver si7006 ={
.probe = si7006_probe,
.remove = si7006_remove,
.driver = {
.name = "hello",
.of_match_table = si7006_tabble,
}
};module_i2c_driver(si7006);
MODULE_LICENSE("GPL");