博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Linux高级驱动】I2C驱动框架分析
阅读量:5759 次
发布时间:2019-06-18

本文共 5770 字,大约阅读时间需要 19 分钟。

1.i2c-dev.c(i2c设备驱动组件层)

    功能:1)给用户提供接口

i2c_dev_init  //入口函数

 /*申请主设备号*/

register_chrdev(I2C_MAJOR(
89),
"i2c",
&i2cdev_fops);
 
/*创建一个设备类*/
 i2c_dev_class
= class_create(THIS_MODULE,
"i2c-dev");
 
/*注册一个i2c驱动*/
 i2c_add_driver(
&i2cdev_driver);
  i2c_register_driver(THIS_MODULE, driver);
   
/*指定总线类型*/
   driver
-
>driver.bus
=
&i2c_bus_type;
   
/*驱动注册
    *1.将i2c驱动加入i2c总线的驱动链表
    *2.搜索设备链表,实现匹配,根据i2c总线的匹配原理:必须要求i2c驱动结构体中实现id_table
    *  但是,i2c驱动结构体中并没有实现id_table,所以永远都匹配失败
    */
   driver_register(
&driver
-
>driver);
    
   
/*搜索适配器链表,每搜索一个适配器,都会调用__process_new_driver函数
    *在此函数中,又会调用i2c驱动中的,attach_adapter函数
    */
   bus_for_each_dev(
&i2c_bus_type, NULL, driver, __process_new_driver);
   __process_new_driver  
//此函数可能会被调用多次
    i2c_do_add_adapter(data, to_i2c_adapter(dev));
     
if (driver
-
>attach_adapter) {
      
/* We ignore the return code; if it fails, too bad */
      driver
-
>attach_adapter(adap);    
//i2cdev_attach_adapter
     }
static
const
struct file_operations i2cdev_fops
= {
 .owner  
= THIS_MODULE,
 .llseek  
= no_llseek,
 .read  
= i2cdev_read,
 .write  
= i2cdev_write,
 .unlocked_ioctl
= i2cdev_ioctl,
 .open  
= i2cdev_open,
 .release
= i2cdev_release,
};
static
struct i2c_driver i2cdev_driver
= {
 .driver
= {
  .name
=
"dev_driver",
 },
 .attach_adapter
= i2cdev_attach_adapter,
 .detach_adapter
= i2cdev_detach_adapter,
};

 

2.i2c-core.c(i2c核心层组件)

    功能:1)注册一条i2c总线

         2)提供基本的接口函数,用来建立上层与下层的连接

i2c_init  
//入口函数
 
/*注册I2C总线*/
 bus_register(
&i2c_bus_type);
   
struct bus_type i2c_bus_type
= {  
//实际的物理总线,I2C总线
 .name  
=
"i2c",
 .match  
= i2c_device_match,  
//匹配函数
 .probe  
= i2c_device_probe,
 .remove  
= i2c_device_remove,
 .shutdown
= i2c_device_shutdown,
 .pm  
=
&i2c_device_pm_ops,
};
static
int i2c_device_match(
struct device
*dev,
struct device_driver
*drv)
{
 
struct i2c_client
*client
= i2c_verify_client(dev);
 
struct i2c_driver
*driver;
 
if (
!client)
  
return
0;
 driver
= to_i2c_driver(drv);
 
/* match on an id table if there is one */
 
if (driver
-
>id_table)
  
return i2c_match_id(driver
-
>id_table, client)
!= NULL;
    
while (id
-
>name[
0]) {
     
if (strcmp(client
-
>name, id
-
>name)
==
0)
      
return id;
     id
++;
    }
 
return
0;
}

涉及的重要结构体:

struct i2c_client {     
//表示一个i2c设备
 
unsigned
short flags;   
/* div., see below  */
 
unsigned
short addr;   
/*器件地址*/
 
char name[I2C_NAME_SIZE];  
/*名字*/
 
struct i2c_adapter
*adapter;
/*所属适配器,所属控制器*/
 
struct i2c_driver
*driver;  
/*设备驱动*/
 
struct device dev;    
/* the device structure  */
 
int irq;      
/* irq issued by device  */
 
struct list_head detected;
};
struct i2c_driver {     
//用来表示i2c驱动
 
unsigned
int
class;
 
/* Notifies the driver that a new bus has appeared or is about to be
  * removed. You should avoid using this if you can, it will probably
  * be removed in a near future.
  */
 
int (
*attach_adapter)(
struct i2c_adapter
*);
 
int (
*detach_adapter)(
struct i2c_adapter
*);
 
/*probe函数:初始化工作,设备检测,*/
 
int (
*probe)(
struct i2c_client
*,
const
struct i2c_device_id
*);
 
int (
*remove)(
struct i2c_client
*);
 
struct device_driver driver;    
//设备驱动
 
const
struct i2c_device_id
*id_table;  
//指定此驱动能为哪些设备服务
 ...
 ...
};
struct i2c_adapter {    
//表示一个i2c适配器/i2c控制器
 
const
struct i2c_algorithm
*algo;
/* the algorithm to access the bus */
  
/*操作方法*/
  
int (
*master_xfer)(
struct i2c_adapter
*adap,
struct i2c_msg
*msgs,
int num);
 
int nr;     
/*适配器的号码*/
 ...
 ...
};
struct i2c_msg {     
//表示一个i2c数据包
 __u16 addr;      
/*设备地址*/
 __u16 flags;     
/*表示:1-表示读包 0-表示写包*/
 __u16 len;      
/*数据包的长度*/
 __u8
*buf;      
/*真正的数据*/
 ...
 ...
};

涉及的重要函数接口:

/*注册一个i2c控制器*/
int i2c_add_adapter(
struct i2c_adapter
*adapter)
int i2c_del_adapter(
struct i2c_adapter
*adap)
/*注册i2c驱动*/
int i2c_add_driver(
struct i2c_driver
*driver)
int i2c_add_numbered_adapter(
struct i2c_adapter
*adap)
int i2c_del_numbered_adapter(
struct i2c_adapter
*adap)
extern
int i2c_del_driver(
struct i2c_driver
*driver);
/*接收i2c数据包*/
int i2c_master_recv(
struct i2c_client
*client,
char
*buf,
int count)
/*发送i2c数据包*/
int i2c_master_send(
struct i2c_client
*client,
const
char
*buf,
int count)
/*提交i2c数据包到总线驱动层*/
int i2c_transfer(
struct i2c_adapter
*adap,
struct i2c_msg
*msgs,
int num)

 

3.busses目录:i2c总线驱动/i2c控制器驱动/i2c适配器驱动

    i2c-s3c2410.c

    功能:1)实现对i2c控制器的初始化

         2)实现操作方法(实现i2c协议,完成数据的发送)

 

如何用通用接口驱动来操作i2c设备

open

app
:  open(
"/dev/i2c-0", O_RDWR);
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
=
sys
:  sys_open
   ...
   ...
i2c
-dev.c
struct file_operations i2cdev_fops
    .open  
= i2cdev_open,
     
/*构建一个i2c_client*/
     
struct i2c_client
*client; 
     
struct i2c_adapter
*adap;  
     
/*获取适配器*/
     adap
= i2c_get_adapter(i2c_dev
-
>adap
-
>nr);
     client
= kzalloc(
sizeof(
*client), GFP_KERNEL);
     client
-
>driver
=
&i2cdev_driver;  
//指定i2c设备驱动
     client
-
>adapter
= adap;     
//指定适配器
     file
-
>private_data
= client;

ioctl

app
:  ioctl(fd, I2C_SLAVE, 0x48)
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
sys
:  sys_ioctl
   ...
   ...
i2c
-dev.c
struct file_operations i2cdev_fops
    .unlocked_ioctl
= i2cdev_ioctl,
     
/*获取i2c_client*/
     
struct i2c_client
*client
= file
-
>private_data;
     
switch (cmd) {
      
case I2C_SLAVE
:    I2C_M_TEN
:是否为
10位寻址的设备
       
if ((arg
> 0x3ff)
||(((client
-
>flags
& I2C_M_TEN)
==
0)
&& arg
> 0x7f))
        
return
-EINVAL;
       client
-
>addr
= arg;  
//0x48
     }

write

app
:  write(fd, wbuf,
1)
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
=
sys
:  sys_write
   ...
   ...
i2c
-dev.c
struct file_operations i2cdev_fops
    .write  
= i2cdev_write,
     
/*获取i2c_client*/
     
struct i2c_client
*client
= file
-
>private_data;
     
char
*tmp;
     tmp
= kmalloc(count, GFP_KERNEL);
     copy_from_user(tmp, buf, count)
     
     
/*发送数据到核心层*/
i2c
-core.c   i2c_master_send(client, tmp, count);
      
struct i2c_msg msg;   
//表示i2c数据包
      
/*填充数据包*/
      msg.addr
= client
-
>addr;    
//0x48
      msg.flags
= client
-
>flags
& I2C_M_TEN;
//写
      msg.len
= count;      
//1
      msg.buf
= (
char
*)buf;     
//wbuf 0x0
      
/*提交数据给总线驱动层*/
      i2c_transfer(adap,
&msg,
1);
       
if (adap
-
>algo
-
>master_xfer) 
i2c_s3c2410.c      adap
-
>algo
-
>master_xfer(adap, msgs, num);   
//s3c24xx_i2c_xfer
         s3c24xx_i2c_xfer
          

 

@成鹏致远

(blogs:http://lcw.cnblogs.com

(emailwwwlllll@126.com)

(qq552158509

转载地址:http://dcmkx.baihongyu.com/

你可能感兴趣的文章
开源中国动弹客户端实践(三)
查看>>
Win 8创造颠覆性体验:预览版关键更新
查看>>
vim在多文件中复制粘贴内容
查看>>
Android ContentObserver
查看>>
疯狂java学习笔记1002---非静态内部类
查看>>
ISA2006实战系列之一:实战ISA三种客户端部署方案(上)
查看>>
TCP服务器
查看>>
AC旁挂三层交换机管理ap,二层接入ap心得
查看>>
JS中比较数字大小
查看>>
springcloud 学习-eureka搭建-为eureka添加认证
查看>>
jQuery插件的开发
查看>>
基础,基础,还是基础之JAVA基础
查看>>
如何成为一个C++高级程序员
查看>>
ant android 打包签名和渠道
查看>>
我的友情链接
查看>>
显式锁(第十三章)
查看>>
看linux书籍做的一些重要笔记(2011.07.03更新)
查看>>
CString、Char* ,char [20]、wchar_t、unsigned short转化
查看>>
从案例学RxAndroid开发(上)
查看>>
Redis学习手册(内存优化)
查看>>