代码中,我添加了很多注释,应该不难理解,有错误大家可以指出来,我再改正

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/i2c.h>
#include <linux/fs.h> #include <asm/uaccess.h> #define I2C_MAJOR 365 //主设备号
#define I2C_MINOR 0 //从设备号
#define I2C_COUNT 1 //设备数量 MODULE_LICENSE("Dual BSD/GPL"); /* 函数声明 */
int s5pc100_i2c_probe(struct i2c_client *, const struct i2c_device_id *);
int s5pc100_i2c_remove(struct i2c_client *);
int s5pc100_i2c_open(struct inode *, struct file *);
int s5pc100_i2c_release(struct inode *, struct file *);
ssize_t s5pc100_i2c_read(struct file *, char __user *, size_t, loff_t *); /* 定义设备结构体 */
typedef struct s5pc100_i2c {
struct i2c_client client;
struct cdev cdev;
}s5pc100_i2c; /* 使用设备结构体 */
s5pc100_i2c *i2c; /* 设备信息struct i2c_device_id结构体,保存i2c设备的设备信息,由于可能
* 存在多个i2c设备所以将它定义为一个结构体数组,方便添加新增设备
struct i2c_device_id {
char name[I2C_NAME_SIZE]; 设备的名字,这是一个宏定义2.6.35中默认是20个字符
ulong driver_data; 设备的私有数据,可以自己随便填写
}
*/
struct i2c_device_id i2c_id[] = {
{
"lm75", 0
},
}; /* 构建i2c子系统的设备驱动结构体i2c_driver
* .driver.name 表示驱动程序的名字,这个名字可以由自己任意取
* .id_table 是一个struct i2c_device_id的结构体,保存着i2c的设备信息
struct i2c_device_id {
char name[I2C_NAME_SIZE]; 设备的名字,这是一个宏定义2.6.35中默认是20个字符
ulong driver_data; 设备的私有数据,可以自己随便填写
}
* .probe 表示匹配成功后要执行的函数
* .remove 表示移除设备的时候要执行的函数 */
struct i2c_driver i2c_driver = {
.driver.name = "lm75",
.id_table = i2c_id,
.probe = s5pc100_i2c_probe,
.remove = s5pc100_i2c_remove,
}; /* 方法绑定结构体 */
struct file_operations i2c_fops = {
.owner = THIS_MODULE,
.open = s5pc100_i2c_open,
.release = s5pc100_i2c_release,
.read = s5pc100_i2c_read,
}; int s5pc100_i2c_open(struct inode * inode, struct file *filp)
{
printk("open\n");
return 0;
} int s5pc100_i2c_release(struct inode * inode, struct file *filp)
{
printk("close\n");
return 0;
} /* 读取设备数据,涉及到struct i2c_msg消息结构体的实现和使用 */
ssize_t s5pc100_i2c_read(struct file *filp, char __user *buf, size_t count, loff_t *loff)
{
int ret = 0;
//定义读写缓冲区
char txbuf[1] = {0};
char rxbuf[2] = {0}; /* i2c设备通讯是通过系统定义的消息结构体实现的,这样可以简化驱动人员的工作,实现驱动的良好移植性.
struct i2c_msg {
__u16 addr; 从机地址,从struct i2c_client中获取
__u16 flags; 标志位,使用下面的宏,其中写数据可以直接传递0进去
#define I2C_M_TEN 0x0010 代表i2c地址为10位地址数据
#define I2C_M_RD 0x0001 读数据,从从机到主机
#define I2C_M_NOSTART 0x4000 if I2C_FUNC_PROTOCOL_MANGLING
#define I2C_M_REV_DIR_ADDR 0x2000 if I2C_FUNC_PROTOCOL_MANGLING
#define I2C_M_IGNORE_NAK 0x1000 if I2C_FUNC_PROTOCOL_MANGLING
#define I2C_M_NO_RD_ACK 0x0800 if I2C_FUNC_PROTOCOL_MANGLING
#define I2C_M_RECV_LEN 0x0400 首先受到的字节表示长度
__u16 len; 消息长度
__u8 *buf; 指向消息数据的指针
}; */
struct i2c_msg msg[2] = {
{ i2c->client.addr, 0, 1, txbuf },
{ i2c->client.addr, I2C_M_RD, 2, rxbuf},
}; if (sizeof(rxbuf) != count)
count = sizeof(rxbuf); ret = i2c_transfer(i2c->client.adapter, msg, ARRAY_SIZE(msg));
if (ret < 0) {
printk("failure:i2c_transfer\n");
return -EFAULT;
} if (copy_to_user(buf, rxbuf, count))
return -EFAULT; return count;
} /* 匹配函数,设备成功配对并取得设备信息struct i2c_client结构体后执行的函数 */
int s5pc100_i2c_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id)
{
int ret = 0;
dev_t devno = MKDEV(I2C_MAJOR, I2C_MINOR); //获取设备号 ret = register_chrdev_region(devno, I2C_COUNT, "i2c"); //注册设备
if (ret < 0) {
printk("failure:register_chrdev_region\n");
return ret;
} /* 申请空间
* 使用函数void *kmalloc(size_t size, gfp_t flags)
size 代表申请的内存大小
flags 表示该函数的操作类型,使用系统提供的宏实现,用到的主要有下面这些:
GFP_ATOMIC 能申请到内存则申请,不能申请到内存则立即返回错误码
GFP_KERNEL 能申请则申请,不能申请则睡眠,直到申请到为止
*/
i2c = (s5pc100_i2c *)kmalloc(sizeof(*i2c), GFP_KERNEL);
if (NULL == i2c) {
printk("failure:i2c.kmalloc\n");
return -ENOMEM;
}
/* 设备初始化,将cdev和file_operations绑定,将设备信息和实现方法进行绑定 */
cdev_init(&i2c->cdev, &i2c_fops);
i2c->cdev.owner = THIS_MODULE;
/* 添加设备 */
ret = cdev_add(&i2c->cdev, devno, I2C_COUNT);
if (ret < 0) {
ret = -EFAULT;
printk("failure:cdev_add\n");
goto err1;
}
/* 导出client,获取系统提供的具体的i2c的设备信息,这样就实现了设备和驱动的关联*/
i2c->client = *client; return 0; err1:
kfree(i2c);
unregister_chrdev_region(devno, I2C_COUNT); return ret;
} /* remove处理函数 */
int s5pc100_i2c_remove(struct i2c_client *client)
{
/* 释放需要释放的数据 */
int ret = 0;
dev_t devno = MKDEV(I2C_MAJOR, I2C_MINOR); cdev_del(&i2c->cdev);
kfree(i2c);
unregister_chrdev_region(devno, I2C_COUNT); return ret;
} /* 加载函数 */
static int __init s5pc100_i2c_init(void)
{
/* 注册i2c的设备驱动
* 使用函数int i2c_add_driver(struct i2c_driver *i2c_driver)
* 成功返回0,失败返回错误码 */
return i2c_add_driver(&i2c_driver);
} /* 卸载函数 */
static void __exit s5pc100_i2c_cleanup(void)
{
/* 删除i2c的设备驱动
* 使用函数void i2c_del_driver(struct i2c_driver *i2c_driver) */
i2c_del_driver(&i2c_driver);
} module_init(s5pc100_i2c_init);
module_exit(s5pc100_i2c_cleanup);

Linux驱动编程--基于I2C子系统的I2C驱动的更多相关文章

  1. linux之i2c子系统架构---总线驱动

    编写i2c设备驱动(从设备)一般有两种方式: 1.用户自己编写独立的从设备驱动,应用程序直接使用即可. 2.linux内核内部已经实现了一个通用的设备驱动,利用通用设备驱动编写一个应用程序(用户态驱动 ...

  2. 基于input子系统的sensor驱动调试(一)

    要想弄明白世界的本质,就要追根溯源:代码也是一样的道理: 最近调试几个sensor驱动,alps sensor驱动.compass sensor驱动.G-sensor驱动都是一样的架构: 一.基于in ...

  3. linux驱动开发—基于Device tree机制的驱动编写

    前言Device Tree是一种用来描述硬件的数据结构,类似板级描述语言,起源于OpenFirmware(OF).在目前广泛使用的Linux kernel 2.6.x版本中,对于不同平台.不同硬件,往 ...

  4. Linux驱动编程--基于I2C子系统的I2C驱动的Makefile

    ifeq ($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd) TEST = ...

  5. 基于input子系统的sensor驱动调试(二)

    继上一篇:http://www.cnblogs.com/linhaostudy/p/8303628.html#_label1_1 一.驱动流程解析: 1.模块加载: static struct of_ ...

  6. (转)Windows驱动编程基础教程

    版权声明     本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括 ...

  7. Linux i2c子系统(一) _动手写一个i2c设备驱动

    i2c总线是一种十分常见的板级总线,本文以linux3.14.0为参考, 讨论Linux中的i2c驱动模型并利用这个模型写一个mpu6050的驱动, 最后在应用层将mpu6050中的原始数据读取出来 ...

  8. Linux i2c子系统(四) _从i2c-s3c24xx.c看i2c控制器驱动的编写

    "./drivers/i2c/busses/i2c-s3c2410.c"是3.14.0内核中三星SoC的i2c控制器驱动程序, 本文试图通过对这个程序的分析, 剥离繁复的细节, 总 ...

  9. 嵌入式Linux内核I2C子系统详解

    1.1 I2C总线知识 1.1.1  I2C总线物理拓扑结构     I2C总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成.通信原理是通过对SCL和SDA线高 ...

随机推荐

  1. 深入学习PHP内核

    http://www.php-internals.com/  深入学习PHP内核 http://www.php-internals.com/book/ http://www.kancloud.cn/@ ...

  2. 项目源码--Android视频MV类网站客户端

    下载源码 技术要点: 1.视频MV类网站客户端框架 2.底部TAB功能模块 3.用户管理模块 4.结合优质动画技术,良好的用户体验 5.用户设置模块 6.sqlite数据库灵活的应用 7.源码带有非常 ...

  3. [golang学习] goroutine调度

    这两天有些闲功夫, 学习下golang, 确实非常简洁. 不过有些缺憾. 在我的测试中. golang的调度(goroutine)似乎不是非常好. func say(k int) { fmt.Prin ...

  4. solr安全-tomcat

    1.1. tomcat部署1 参考文档:solr安全机制 1.1.1. 加上安全机制的必要性 在前面有提到, Solr 本身是不加安全机制的, 所有的查詢.admin.update 這些指令都可以經由 ...

  5. 转js contains 方法

    function Jcontains(root, el) { if (root.compareDocumentPosition) return root === el || !!(root.compa ...

  6. 【阿里云产品公测】大数据下精确快速搜索OpenSearch

    [阿里云产品公测]大数据下精确快速搜索OpenSearch 作者:阿里云用户小柒2012 相信做过一两个项目的人都会遇到上级要求做一个类似百度或者谷歌的站内搜索功能.传统的sql查询只能使用like ...

  7. 通用权限底层研究:Web应用限制IP访问的功能实现

    如果你的web应用受到恶意扫描或攻击,你会怎么处理呢?大多数时候从应用日志里可以看到恶意扫描或攻击,遇到此类情况,如有一个可以进行IP访问控制的功能就好些了. 现将在MVC下实现的一个IP访问限制功能 ...

  8. web前端开发(5)

    CSS的一些问题: 一般情况下,尽量使用class选择器 解决点击超链接后hover 样式不出现多次问题:a:visited  a:hover 的顺序是问题所在,记住 love hate  L(lin ...

  9. Linux中的特殊权限粘滞位(sticky bit)详解

    Linux下的文件权限 在linux下每一个文件和目录都有自己的访问权限,访问权限确定了用户能否访问文件或者目录和怎样进行访问.最为我们熟知的一个文件或目录可能拥有三种权限,分别是读.写.和执行操作, ...

  10. page59-一种能够累加数据的ADT(可视化版本) [可用于数据挖掘可视化工具]

    public class VisualAccumulator VisualAccumulator() 创建一个累加器 void addDataValue(double val) 添加一个新的数据值 d ...