//驱动层
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
struct s5pv210_i2c{
struct i2c_client * client;
};
struct s5pv210_i2c * i2c;
int at24c02_i2c_write(struct i2c_client * client, char * buf, int count)
{
int ret;
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = 0;
msg.buf = buf;
msg.len = count;
ret = i2c_transfer(client->adapter, &msg, 1);
return ret == 1? count : ret;
}
int at24c02_i2c_read(struct i2c_client * client, char * buf, int count)
{
int ret;
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = 1;
msg.buf = buf;
msg.len = count;
ret = i2c_transfer(client->adapter, &msg, 1);
return ret == 1? count : ret;
}
ssize_t i2c_driver_read(struct file * filp, char __user * buff, size_t count, loff_t * pos)
{
int ret;
char * buf;
// 1.判断参数的合法性
if(count < 0 || count > 255)
return -EINVAL;
// 2.分配空间
buf = kzalloc(count, GFP_KERNEL);
if(buf == NULL)
{
printk("kzalloc error\n");
return -ENOMEM;
}
// 3.通过i2c总线读取从设备数据
ret = at24c02_i2c_read(i2c->client, buf, count);
if(ret < 0)
{
printk("at24c02_i2c_read error\n");
goto kzalloc_err;
}
// 4.把数据给用户空间
ret = copy_to_user(buff, buf, count);
if(ret > 0)
{
printk("copy_to_user error\n");
goto kzalloc_err;
}
kfree(buf);
return count;
kzalloc_err:
kfree(buf);
return ret;
}
ssize_t i2c_driver_write(struct file * filp, const char __user * buff, size_t count, loff_t * pos)
{
int ret;
char * buf;
// 1.判断参数的合法性
if(count < 0 || count > 255)
return -EINVAL;
// 2.分配空间
buf = kzalloc(count, GFP_KERNEL);
if(buf == NULL)
{
printk("kzalloc error\n");
return -ENOMEM;
}
// 3.把用户空间的数据拷贝到内核空间
ret = copy_from_user(buf, buff, count);
if(ret > 0)
{
printk("copy_from_user error\n");
goto kzalloc_err;
}
// 4.把数据通过i2c总线传递给从设备
//i2c_master_send(const struct i2c_client * client, const char * buf, int count)
//i2c_master_recv(const struct i2c_client * client, char * buf, int count)
ret = at24c02_i2c_write(i2c->client, buf, count);
if(ret < 0)
{
printk("at24c02_i2c_write error\n");
ret = -EFAULT;
goto kzalloc_err;
}
kfree(buf);
return count;
kzalloc_err:
kfree(buf);
return ret;
}
const struct file_operations i2c_fops = {
.read = i2c_driver_read,
.write = i2c_driver_write,
};
struct miscdevice misc = {
.minor = 199,
.name = "fs210_i2c",
.fops = &i2c_fops,
};
int i2c_driver_probe(struct i2c_client * client, const struct i2c_device_id * id_table)
{
int ret;
// 1. 创建全局结构体对象
i2c = kzalloc(sizeof(struct s5pv210_i2c), GFP_KERNEL);
if(i2c == NULL)
{
printk("kzalloc error\n");
return -ENOMEM;
}
i2c->client = client;
// 2. 注册杂项设备
ret = misc_register(&misc);
if(ret < 0)
{
printk("misc_register error\n");
goto kzalloc_err;
}
// 3. 硬件初始化(本实验不需要)
return 0;
kzalloc_err:
kfree(i2c);
return ret;
}
int i2c_driver_remove(struct i2c_client * client)
{
misc_deregister(&misc);
kfree(i2c);
return 0;
}
const struct i2c_device_id table[] = {
{"at24c02a", 0x1234},
{"at24c04a", 0x2234},
};
struct i2c_driver drv = {
.probe = i2c_driver_probe,
.remove = i2c_driver_remove,
.driver = {
.name = "e2prom_i2c",
},
.id_table = table,
};
static int __init i2c_drv_init(void)
{
return i2c_add_driver(&drv);
}
static void __exit i2c_drv_exit(void)
{
i2c_del_driver(&drv);
}
module_init(i2c_drv_init);
module_exit(i2c_drv_exit);
MODULE_LICENSE("GPL");
//应用层
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
// ./xxx w data ---- 写数据
// ./xxx r
int main(int argc, char ** argv)
{
int fd;
unsigned char value;
unsigned char wbuff[10];
unsigned char rbuff[10];
unsigned char register_addr = 0x08;
if(argc < 2)
{
printf("Usage:%s w data --->write e2prom\n", argv[0]);
printf("Usage:%s r --->read e2prom\n", argv[0]);
}
fd = open("/dev/fs210_i2c",O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
if(strcmp(argv[1], "r") == 0)//读数据
{
if(write(fd, ®ister_addr, 1) != 1)
{
perror("write");
exit(1);
}
if(read(fd, rbuff, 1) != 1)
{
perror("read");
exit(1);
}
printf("rbuf:0x%x\n",rbuff[0]);
}
else//写数据
{
value = strtoul(argv[2], NULL, 0);
wbuff[0] = register_addr;
wbuff[1] = value;
if(write(fd, wbuff, 2) != 2)
{
perror("write");
exit(1);
}
printf("Write OK!\n");
}
return 0;
}