linux驱动

第一章 linux驱动之设备与驱动
第二章 linux驱动之设备树与GPIO子系统


linux驱动之总线详解

  • linux驱动
  • 一、总线bus
    • 1.bus在linux中文件结构
    • 2.bus_type
    • 3.常用的系统函数
  • 二、Platform设备驱动
    • 1.platform
    • 2.platform设备
    • 3.platform驱动
    • 4.platform设备驱动细节
  • 三、I2C
    • 1.IIC总线
    • 2.I2C在linux下的结构
    • 2.I2C中主要的结构体
    • 3.i2c的系统调用函数

一、总线bus

1.bus在linux中文件结构

在linux系统中,在sys/bus文件夹下存放的文件夹都是实例化的总线,比如platform,i2c等等,而这些文件夹下又存放着device和driver文件夹,这些则是存放在该总线下的设备与驱动。
每个实例化的bus会规定在该bus下的device和driver的匹配方式,并建立链表将所有device和driver建立联系,

2.bus_type

1.每个sys/bus文件夹下的文件夹都是bus_type的实例化对象,其中match指向device和driver和匹配方式

每个sys/bus文件夹下的文件夹都是bus_type的实例化对象,其中match指向device和driver和匹配方式函数
struct bus_type { const char *name; /* 总线名字 */
const char *dev_name;
struct device *dev_root;
struct device_attribute *dev_attrs;
const struct attribute_group **bus_groups; /* 总线属性 */
const struct attribute_group **dev_groups; /* 设备属性 */ const struct attribute_group **drv_groups; /* 驱动属性 */ int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev); int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*online)(struct device *dev);
int (*offline)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state); /*当设备收到 suspend 命令的时候,就会执行这个函数*/
int (*resume)(struct device *dev); /*当设备收到 resume 命令的时候,就会执行这个函数*/
const struct dev_pm_ops *pm;
const struct iommu_ops *iommu_ops;
struct subsys_private *p;
struct lock_class_key lock_key;
}

2.每个实例化的bus(xbus)都会有这样的一个结构,xbus通过此结构与device和driver建立联系,同时此结构也规定了在xbus下的匹配方式等。

3.常用的系统函数

总线初始化: buses_init()

  • 开机运行
  • 创建kset,后面的相关操作会将所有的实例化的bus(xbus)连到kset

总线注册:bus_register()函数int bus_register(struct bus_type *bus)

  • 在/sys/bus下建立xbus目录项,并创建属性文件
  • 在/sys/bus/xbus下建立devices目录项,并创建属性文件
  • 在/sys/bus/xbus下建立drivers目录项,并创建属性文件
  • 初始化 priv->klist_devices链表头
  • 初始化priv->klist_drivers链表头

设备注册:int device_register(struct device *dev)

  • 在/sys/bus/xbus/devices下建立yyy目录项
  • 加入bus-> priv->devices_kset链表
  • 加入bus-> priv->klist_devices链表
  • 遍历bus-> priv->klist_drivers,执行bus->match()寻找合适的drv
  • dev关联driv,执行drv->probe()

驱动注册:int driver_register(struct device_driver *drv)

  • 在/sys/bus/xbus/drivers下建立zzz目录项
  • 加入bus-> priv->drivers_kset链表
  • 加入bus-> priv->klist_drivers链表
  • 遍历bus-> priv->klist_klist_devices链表,执行bus->match()寻找合适的dev
  • dev关联dev,执行drv->probe()

二、Platform设备驱动

1.platform

platform作为bus的一个实例化的总线,系统提供了platform_device_register(&beep_device)和platform_driver_register(&beep_driver)向platform注册,同时系统也提供了platform_device_unregister(&beep_device)和platform_driver_unregister(&beep_device)向platform删除device和driver。每次注册和删除device和diver时,paltform的device和driver文件夹下都会添加和删除对应的文件。

struct bus_type platform_bus_type =
{
.name = "platform",
.dev_groups = platform_dev_groups, .match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops, };

2.platform设备

Platform设备常用函数和基本流程
1.定义平台设备机构体:struct platform_device。
2.注册平台设备:platform_device_register(&beep_device);
3.卸载平台设备:platform_device_unregister(&beep_device);

/** @Author: topeet* @Description: 基于平台设备模型的device.c*/
#include <linux/init.h>     //初始化头文件
#include <linux/module.h>   //最基本的文件,支持动态添加和卸载模块。
#include <linux/platform_device.h> //平台设备所需要的头文件
/*** @description: 释放 flatform 设备模块的时候此函数会执行* @param {structdevice} *dev:要释放的设备* @return {*}*/
void beep_release(struct device *dev)
{printk("beep_release \n");
}
// 设备资源信息,也就是蜂鸣器所使用的所有寄存器
struct resource beep_res[] = {[0] = {.start = 0x020AC000,//寄存器组的起始地址.end = 0x020AC003,//寄存器组的终止地址.flags = IORESOURCE_MEM,.name = "GPIO5_DR",}};
// platform 设备结构体
struct platform_device beep_device = {.name = "beep_test",.id = -1,.resource = beep_res,.num_resources = ARRAY_SIZE(beep_res),.dev = {.release = beep_release}};
/*** @description:  设备模块加载* @param {*}无* @return {*}无*/
static int device_init(void)
{// 设备信息注册到 Linux 内核platform_device_register(&beep_device);printk("platform_device_register ok \n");return 0;
}
/*** @description: 设备模块注销* @param {*}无* @return {*}无*/
static void device_exit(void)
{// 设备信息卸载platform_device_unregister(&beep_device);printk("gooodbye! \n");
}
module_init(device_init);
module_exit(device_exit);
MODULE_LICENSE("GPL");

3.platform驱动

Platform设备常用函数和基本流程
1.定义平台设备机构体:struct platform_driver。
2.注册平台设备:platform_driver_register(&beep_driver);
3.卸载平台设备:platform_driver_unregister(&beep_device);

/** @Author:topeet* @Description: 基于平台设备模型的driver.c*/
#include <linux/init.h>   //初始化头文件
#include <linux/module.h>  //最基本的文件,支持动态添加和卸载模块。
#include <linux/platform_device.h>//平台设备所需要的头文件
/*** @description: beep_probe,驱动和设备匹配成功会进入此函数* @param {structplatform_device} *pdev* @return {*}*/
int beep_probe(struct platform_device *pdev){printk("beep_probe\n");return 0;}
/*** @description: beep_remove,当driver和device任意一个remove的时候,就会执行这个函数* @param {structplatform_device} *pdev* @return {*}*/
int beep_remove(struct platform_device *pdev){printk("beep_remove\n");return 0;
}
// 该设备驱动支持的设备的列表 ,他是通过这个指针去指向 platform_device_id 类型的数组
const struct platform_device_id beep_idtable = {.name = "beep_test", //设备名字叫“beep_test”
};// platform 驱动结构体
struct platform_driver beep_driver = {.probe = beep_probe,.remove = beep_remove,.driver={.owner = THIS_MODULE,.name = "beep_test"},.id_table = &beep_idtable
};
/*** @description: 设备模块加载* @param {*}无* @return {*}无*/
static int beep_driver_init(void){int ret = 0;// platform驱动注册到 Linux 内核ret = platform_driver_register(&beep_driver);if(ret<0){printk("platform_driver_register error \n");}printk("platform_driver_register ok \n");return 0;
}
/*** @description: 设备模块注销* @param {*}无* @return {*}无*/
static void beep_driver_exit(void){// platform驱动卸载platform_driver_unregister(&beep_driver);printk("gooodbye! \n");
}
module_init(beep_driver_init);
module_exit(beep_driver_exit);
MODULE_LICENSE("GPL");

4.platform设备驱动细节

Platform注意要点:
1.Platform_driver中的.driver,.id_table都含有name变量,会自动与Platform_device中的name匹配,
.id_table的优先级要高于.driver,只有当.id_table没有匹配上时,才会匹配.driver。
2.Platform_driver和Platform_device匹配成功时会自动调用Platform中.probe指向的函数。

三、I2C

1.IIC总线

IIC作为BUS_TYPE中的一个实例化的对象,也继承了BUS_TYPE的结构。
linux启动之后,默认执行i2c_init,在i2c_init中调用bus_register(&i2c_bus_type)将IIC总线实例化。

    struct bus_type i2c_bus_type = {.name           = "i2c",.match          = i2c_device_match,.probe          = i2c_device_probe,.remove         = i2c_device_remove,.shutdown       = i2c_device_shutdown,};

2.I2C在linux下的结构

每个IIC设备都会指向一个IIC适配器,适配器结构体中存在Algorithm,Algorithm中存在一系列函数指针,这些函数指针指向真正硬件操作代码。
每个client都指向IIC适配器,每个适配器都是一个设备,都有对应的驱动。适配器的驱动是在platform下定义的,系统在开机后会自动完成每个适配器的驱动,并将适配器的信息记录到imx_i2c_struct中,此结构体不仅有适配器的信息,同时海记录了IIC的其他信息,供驱动开发人员查看。

2.I2C中主要的结构体

适配器:struct i2c_adapter

/** i2c_adapter is the structure used to identify a physical i2c bus along* with the access algorithms necessary to access it.*/
struct i2c_adapter {struct module *owner;unsigned int class;               /* classes to allow probing for */const struct i2c_algorithm *algo; /* the algorithm to access the bus */void *algo_data;/* data fields that are valid for all devices   */struct rt_mutex bus_lock;int timeout;                    /* in jiffies */int retries;struct device dev;              /* the adapter device */int nr;char name[48];struct completion dev_released;struct mutex userspace_clients_lock;struct list_head userspace_clients;struct i2c_bus_recovery_info *bus_recovery_info;const struct i2c_adapter_quirks *quirks;
};struct i2c_algorithm {/* If an adapter algorithm can't do I2C-level access, set master_xferto NULL. If an adapter algorithm can do SMBus access, setsmbus_xfer. If set to NULL, the SMBus protocol is simulatedusing common I2C messages *//* master_xfer should return the number of messages successfullyprocessed, or a negative value on error */int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,unsigned short flags, char read_write,u8 command, int size, union i2c_smbus_data *data);/* To determine what the adapter supports */u32 (*functionality) (struct i2c_adapter *);#if IS_ENABLED(CONFIG_I2C_SLAVE)int (*reg_slave)(struct i2c_client *client);int (*unreg_slave)(struct i2c_client *client);
#endif
};

i2c从设备:struct i2c_client

adapter指向负责该设备的adapterstruct i2c_client {unsigned short flags;           /* div., see below              */unsigned short addr;            /* chip address - NOTE: 7bit    */char name[I2C_NAME_SIZE];struct i2c_adapter *adapter;    /* the adapter we sit on        */struct device dev;              /* the device structure         */int init_irq;                   /* irq set at initialization    */int irq;                        /* irq issued by device         */struct list_head detected;#if IS_ENABLED(CONFIG_I2C_SLAVE)i2c_slave_cb_t slave_cb;        /* callback for slave mode      */#endif};flags: :I2C_CLIENT_TEN表示设备使用10位芯片地址,I2C客户端PEC表示它使用SMBus数据包错误检查addr: addr在连接到父适配器的I2C总线上使用的地址。name: 表示设备的类型,通常是芯片名。adapter: struct i2c_adapter 结构体,管理托管这个I2C设备的总线段。dev: Driver model设备节点。init_irq: 作为从设备时的发送函数。irq: 表示该设备生成的中断号。detected: struct list_head i2c的成员_驱动程序.客户端列表或i2c核心的用户空间设备列表。slave_cb: 使用适配器的I2C从模式时回调。适配器调用它来将从属事件传递给从属驱动程序。i2c_客户端识别连接到i2c总线的单个设备(即芯片)。暴露在Linux下的行为是由管理设备的驱动程序定义的。

i2c设备驱动:struct i2c_driver

    struct i2c_driver {unsigned int class;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;int (*detect)(struct i2c_client *, struct i2c_board_info *);const unsigned short *address_list;struct list_head clients;...};
probe: i2c设备和i2c驱动匹配后,回调该函数指针。
id_table: struct i2c_device_id 要匹配的从设备信息。
address_list: 设备地址
clients: 设备链表
detect: 设备探测函数

开机时,系统内核会调用i2c_adap_imx_init,开机后的系统已经注册了i2c_imx_driver驱动,此驱动会和IIC的设备树配对,完成adapter的设置。同时创建imx_i2c_struct结构体。此结构体记录了IIC的一些配置,系统可以通过此结构体获得IIC的参数。
I.MX6U 的 I2C 适配器驱动是个标准的 platform 驱动,由此可以看出,虽然 I2C 总线为别的设备提供了一种总线驱动框架,但是 I2C 适配器却是 platform驱动。

static int __init i2c_adap_imx_init(void)
{return platform_driver_register(&i2c_imx_driver);
}struct imx_i2c_struct {struct i2c_adapter      adapter;//适配器struct clk              *clk;void __iomem            *base;wait_queue_head_t       queue;unsigned long           i2csr;unsigned int            disable_delay;int                     stopped;unsigned int            ifdr; /* IMX_I2C_IFDR */unsigned int            cur_clk;unsigned int            bitrate;const struct imx_i2c_hwdata     *hwdata;struct imx_i2c_dma      *dma;
};
clk: clk结构体保存时钟相关信息
bitrate: 保存i2c的波特率
dma: struct imx_i2c_dma 结构体 dam相关信息等等

3.i2c的系统调用函数

IIC核心提供一些APIint i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
void i2c_del_adapter(struct i2c_adapter * adap)int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
int i2c_add_driver (struct i2c_driver *driver)
void i2c_del_driver(struct i2c_driver *driver)struct i2c_adapter *i2c_get_adapter(int nr);//获取编号为nr的I2C适配器
void i2c_put_adapter(struct i2c_adapter *adap);//释放adap指向的适配器
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);//把 I2C 适配器和 I2C 器件关联起来
void i2c_unregister_device(struct i2c_client *client)//功能 注销一个 client。

数据传输系统函数,函数最终就是调用我们前面讲到的i2c_imx_xfer()函数来实现数据传输
struct i2c_msg {__u16 addr;     /* slave address                        */__u16 flags; //flags: 消息传输方向和特性。I2C_M_RD:表示读取消息;0:表示发送消息。...__u16 len;              /* msg length                           */__u8 *buf;              /* pointer to msg data                  */};
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
int i2c_master_send(const struct i2c_client *client,const char *buf, int count)
int i2c_master_recv(const struct i2c_client *client,char *buf, int count)
int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf,int count, u16 flags){int ret;struct i2c_msg msg = {.addr = client->addr,.flags = flags | (client->flags & I2C_M_TEN),.len = count,.buf = buf,};ret = i2c_transfer(client->adapter, &msg, 1);/** If everything went ok (i.e. 1 msg transferred), return #bytes* transferred, else error code.*/return (ret == 1) ? count : ret;}

linux驱动之总线详解相关推荐

  1. linux驱动双摄像头,详解linux 摄像头驱动编写

    对于现代嵌入式设备,特别是手机来说,摄像头是很重要的一个设备.很多同学买手机,一看颜值,第二就看摄像头拍照如何.所以,从某个角度来说,摄像头是各个厂家主打的应用功能.那么,linux是如何支持摄像头的 ...

  2. 【正点原子Linux连载】第三十五章 Linux内核顶层Makefile详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  3. 15、Windows驱动开发技术详解笔记(11) 基本概念

    9.Windows驱动程序的入口函数规定为_DriverEntry@8,所以用C++编写时要用extern. 驱动程序中,不能使用编译器运行时函数,甚至C语言中的malloc,C++的new函数都不能 ...

  4. 《Windows驱动开发技术详解》学习笔记

    Abstract   如果推荐 Windows 驱动开发的入门书,我强烈推荐<Windows驱动开发技术详解>.但是由于成书的时间较早,该书中提到的很多工具和环境都已不可用或找不到,而本文 ...

  5. STM32L475 SPI驱动LCD ST7789V2详解

    概述 最近在学习正点原子潘多拉开发板,在此结合原子哥的代码, 对SPI驱动LCD做一个详细介绍. TFTLCD 和 SPI TFTLCD介绍 TFT-LCD 即薄膜晶体管液晶显示器.其英文全称为:Th ...

  6. linux命令之-dmesg详解

    Linux命令dmesg用法详解 功能说明:显示开机信息.  语 法:dmesg [-cn][-s <缓冲区大小>]  补充说明:kernel会将开机信息存储在ring buffer中.您 ...

  7. Kali linux无线网络渗透详解笔记

    Kali linux无线网络渗透详解笔记 第一章:搭建渗透环境测试环境 第二章:WiFi网络的构成 第三章:监听WiFi网络 第四章:捕获数据包 第五章: 分析数据包 第六章:获取信息 第七章:WPS ...

  8. linux远程date命令,linux之date命令详解

    date命令的用处 1.用于显示特殊的时间格式,可以用于对日志文件的命名 2.用于设置时间 ,不过这方面用的比较少,因为一般的服务器都设置的有自动同步网络时间 用法: date [OPTION]... ...

  9. linux 命令xargs,Linux下xargs命令详解

    Linux下xargs命令详解 1. 简介   之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了xargs命令,例如: find /sbin -pe ...

最新文章

  1. 数学中的span以及线性流形是什么意思
  2. Windows7瘦身和备份
  3. 做爱做的事,做有快感的事
  4. ASP.NET中进行消息处理(MSMQ) 二
  5. 基础 - jQuery选项卡
  6. 搭建高可用的rabbitmq集群 + Mirror Queue + 使用C#驱动连接
  7. Tomcat启动时自动加载Servlet
  8. Mapnik使用postgres中的栅格数据
  9. CentOS 使用yum update 更新时保留特定版本的软件
  10. 如何从零开始搭建自己的博客
  11. 设计模式笔录(一),什么是设计模式
  12. paip.c#.net 右键菜单带图标
  13. latex数学符号加粗_latex 数学符号加粗
  14. python关键词排名批量查排名_Python 批量获取Baidu关键词的排名并入库
  15. App架构设计经验谈
  16. JAVA--多线程管理
  17. 《软件设计师》备考笔记
  18. php破解referer防盗链解析,Referer原理与图片防盗链实现方法详解
  19. matlab 为双y轴加标签,[转载]matlab双y轴添加误差棒(转载)
  20. Java中将对象转换成String的三种方法

热门文章

  1. 矩阵开根号_CVPR2018论文阅读-Faster MPN-COV:迭代计算矩阵平方根以快速训练全局协方差池...
  2. Hands On Machine Learning with Scikit Learn and TensorFlow(第三章)
  3. wow服务器维护8月14,8月14日服务器例行维护公告(已完成)
  4. 腾讯海外游戏直播Android开发面经
  5. 花嫁之容氏浅浅最后怎么样了_花嫁之容氏浅浅大结局最后章节第2章免费看
  6. 网络技术入门(一):网络技术基础知识系统归结
  7. 10个实用的UX设计作品推销小窍门
  8. C++学习--台阶问题
  9. fig翻译_Fig. 2. (a) Loading equipment; (b) Distributi简体中文怎么写 - 什么意思? - 怎么翻译?...
  10. 香橙派全志H3烧入U-boot和Linux内核以及配置