一、platform 设备驱动

1.1 platform 总线、设备与驱动

在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

Linux发明了一种虚拟的总线,称为platform总线, 相应的设备成为platform_device, 而驱动成为platform_driver。

platform_device结构体

struct platform_device {

const char *name; //设备名

u32id;

struct device dev;

u32num_resource; //设备所使用的各类资源数量

struct resource * resource; //资源

};

platform_driver结构体

struct platform_driver {

int (*probe) (struct platform_device *);

int (*remove) (struct platform_device *);

void (*shutdown) (struct platform_device *);

int (*suspend) (struct platform_device *, pm_message_t state);

int (*suspend_late) (struct platform_device *, pm_message_t state);

int (*resume_early) (struct plartform_device *);

int (*resume) (struct platform_device *);

struct pm_ext_ops *pm;

struct device_driver driver;

};

系统中为platform总线定义了一个bus_type的实例platform_bus_type,其定义如代码清单:

struct bus_type platform_bus_type = {

.name= "platform",

.dev_attrs= platform_dev_attrs,

.match = platform_match,

.uevent= platform_uevent,

.pm= PLATFORM_PM_OPS_PTR,

};

EXPORT_SYMBOL_GPL(platform_bus_type);

这里要重点关注其match() 成员函数, 正是此成员函数确定了platform_device 和 platform_driver之间如何匹配,代码如下:

static int platform_match (struct device *dev, struct device_driver *drv)

{

struct platform_device *pdev;

pdev = container_of(dev, struct platform_device, dev);

return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);

};    //匹配platform_device和platform_driver主要看两者的name字段是否相同。

对platform_device的定义通常在BSP的板文件中实现,在板文件中,将platform_device归纳为一个数组,最终通过platform_add_devices()函数统一注册。platform_add_devices()函数可以将平台设备添加到系统中,这个函数的原型为:

int platform_add_devices(struct platform_device **devs, int num); //该函数的第一个参数为平台设备数组的指针,第二个参数为平台设备的数量,它的内部调用了platform_device_register() 函数用于注册单个的平台设备。

1.2 输入设备驱动

输入核心提供了底层输入设备驱动程序所需的API,如分配/释放一个输入设备:

struct input_dev *input_allocate_device(void);

void input_free_device(struct input_dev * dev);

input_allocate_device()返回的是一个input_dev 的结构体,此结构体用于表征1个输入设备。

注册/注销输入设备用的接口如下:

int _ _must_check input_register_device(struct input_dev *);

void input_unregister_device(struct input_dev *);

报告输入事件用的接口如下:

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); //报告指定type、code的输入事件

void input_report_key(struct input_dev *dev, unsigned int code, int value); //报告键值

void input_report_rel(struct input_dev *dev, unsigned int code, int value); //报告相对坐标

void input_report_abs(struct input_dev *dev, unsigned int code, int value); //报告绝对坐标

void input_sync(struct input_dev *dev); //报告同步事件

而所有的输入事件,内核都用统一的数据结构来描述,这个数据结构是input_event, 形如代码如下:

struct input_event {

struct timeval time;

_ _u16 type;

_ _u16 code;

_ _s32 value;

};

二:输入设备驱动

输入核心提供了底层输入设备驱动程序所需的API,如分配、释放一个初入设备:

struct input_dev *input_allocate_device(void);

void input_free_device(struct input_dev *dev);

注册/注销输入设备用的接口如下:

int _ _must_check input_register_device(struct input_dev *);

void input_unregister_device(struct input_dev *);

报告输入事件用的接口如下:

/*报告制定type、code的输入事件*/

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);

/*报告键值*/

void input_report_key(struct input_dev *dev, unsigned int code, int value);

/*报告相对坐标*/

void input_report_rel(struct input_dev *dev, unsigned int code, int value);

/*报告绝对坐标*/

void input_report_abs(struct input_dev *dev, unsigned int code, int value);

/*报告同步事件*/

void input_sync(struct input_dev *dev);

而所有的输入事件,内核都用统一的数据结构来描述,这个数据结构是input_event,形如代码清单:

struct input_event {

struct timeval time;

_ _u16 type;

_ _u16 code;

_ _s32 value;

};

三、Linux SPI主机和设备驱动

SPI(同步外设接口)是由摩托罗拉公司开发的全双工同步串行总线,其接口由MISO(串行数据输入)、MOSI(串行数据输出)、SCK(串行移位时钟)、SS(从使能信号)4种信号构成,SS决定了惟一的与主设备通信的从设备,主设备通过产生移位时钟来发起通信。通信时,数据由MOSI输出,MISO输入,数据在时钟的上升或下降沿由MOSI输出,在紧接着的下降或上升沿由MISO读入,这样经过8/16次时钟的改变,完成8/16位数据的传输。

SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性(CPOL)和相位(CPHA)可以进行配置。如果CPOL = 0,串行同步时钟的空闲状态为低电平;如果CPOL = 1,串行同步时钟的空闲状态为高电平。如果CPHA = 0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA =  1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。

在Linux中,用代码清单的spi_master结构体来描述一个SPI主机控制器驱动,其主要成员是主机控制器的序号(系统中可能存在多个SPI主机控制器)、片选数量、SPI模式和时钟设置用到的函数、数据传输用到的函数等。

struct spi_master {

struct device dev;

s16 bus_num;

u16 num_chipselect;

int (*setup) (struct spi_device *spi); //设置模式和时钟

int (*transfer) (struct spi_device *spi, struct spi_message *mesg); //双向数据传输

void (*cleanup) (struct spi_device *spi);

}

分配、注册和注销SPI主机的API由SPI核心提供:

struct spi_master * spi_alloc_master(struct device *host, unsigned size);

int spi_register_master(struct spi_master *master);

void spi_unregister_master(struct spi_master *master);

在Linux中,用代码清单spi_driver结构体来描述一个SPI外设驱动,可以认为是spi_master的client驱动。

struct spi_driver {

int (*probe)(struct spi_device *spi);

int (*remove)(sturct spi_device *spi);

int (*shutdown)(struct spi_device *spi);

int  (*suspend)(struct spi_device *spi);

int  (*resume)(struct spi_device *spi);

struct device_driver driver;

};

在SPI外设驱动中,当透过SPI总线进行数据传输的时候,使用了一套与CPU无关的统一的接口。这套接口的第一个关键数据结构就是spi_transfer,它用于描述SPI传输,如代码清单所示:

struct spi_transfer {

const void  *tx_buf;

void  *rx_buf;

unsigned  len;

dma_addr_t tx_dma;

dma_addr_t rx_dma;

unsigned  cs_chang:1;

u8  bits_per_word;

u16 delay_usecs;

u32 speed_hz;

struct list_head stransfer_list;

};

而一次完整的SPI传输流程可能不只包含一次spi_transfer, 他可能包含一个或多个spi_transfer, 这些spi_transfer最终通过spi_message组织在一起,定义代码如下:

struct spi_message {

struct list_head transfers;

struct spi_device *spi;

unsigned  is_dma_mapped:1;

/*完成被一个callback报告*/

void (*complete) (void *context);

void  *context;

unsigned  actual_length;

int  status;

struct list_head queue;

void  *state;

};

通过spi_message_init() 可以初始化spi_message,而将spi_transfer添加到spi_message队列的方法则是:

void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m);

发起一次spi_message的传输有同步和异步两种方式,同步API时,会阻塞等待这个消息被处理完。同步操作时使用的API是:

int spi_sync( struct spi_device *spi, struct spi_message *message);

使用异步API时,不会阻塞等待这个消息被处理完,但是可以在spi_message的complete字段接一个回调函数,当消息被处理完成后,该函数会被调用。异步操作时使用的API是:

int spi_async(struct spi_device *spi, struct spi_message *message);

工程中的Linux设备驱动相关推荐

  1. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

  2. linux设备驱动总结,《Linux设备驱动开发详解(第3版)》海量更新总结

    本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 2015.2.26 几乎完成初稿. [F]是修正或升级:[N]是新增知识点:[D]是删除的内容 第1章 <Linux ...

  3. 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)进展同步更新

    本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 目前已经完成稿件. 2015年8月9日,china-pub开始上线预售: http://product.china-pub ...

  4. 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)网购链接

    <Linux设备驱动开发详解:基于最新的Linux 4.0内核> china-pub   天猫     dangdang   京东 China-pub 8月新书销售榜 推荐序一 技术日新月 ...

  5. linux设备驱动第五篇:驱动中的并发与竟态

    目录[-] 综述 信号量与互斥锁 Completions 机制 自旋锁 其他的一些选择 不加锁算法 原子变量与位操作 seqlock(顺序锁) 读取-拷贝-更新(RCU) 小结 综述 在上一篇介绍了l ...

  6. Linux设备驱动中的并发控制总结

    并发(concurrency)指的是多个执行单元同时.并行被执行.而并发的执行单元对共享资源(硬件资源和软件上的全局.静态变量)的访问则容易导致竞态(race conditions).   SMP是一 ...

  7. linux 两个驱动 竞态,第7章 Linux设备驱动中的并发控制之一(并发与竞态)

    本章导读 Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发的访问会导致竞态(竞争状态). Linux提供了多种解决竞态问题的方式,这些方式适合不同的应用场景. 7.1讲解了并 ...

  8. Linux 设备驱动开发 —— 设备树在platform设备驱动中的使用

    关与设备树的概念,我们在Exynos4412 内核移植(六)-- 设备树解析 里面已经学习过,下面看一下设备树在设备驱动开发中起到的作用 Device Tree是一种描述硬件的数据结构,设备树源(De ...

  9. Linux中kobject的作用,Linux设备驱动模型-- 数据结构Kset/KObject

    前言 Kset和kobject是Linux设备驱动模型中的核心数据结构,其主要作用是将系统中的设备抽象出来,以树状结构组织,方便系统统一管理. 而这个统一管理的地方,就是sysfs,先放一张示例图,阐 ...

最新文章

  1. CCNA 第二学期答案
  2. Mips KVM TrapEmulate implemented in Linux
  3. python发邮件详解_python实现发送邮件详解
  4. centos安装mysql-python_在Centos上安装mysql python
  5. MySQL(基础技能)
  6. ubuntu 启动时显示initramfs 无法进入系统
  7. AWR6843芯片使用JFlash下载外部NorFlash
  8. 计算机与医疗PPT,《人工智能医药》ppt课件
  9. 超硬核 | 一文带你入门用户画像
  10. 微一案做php,微一案:真正的高效率,都是这么炼成的
  11. 自媒体必备工具:免费的音文对齐生成SRT字幕,快速打轴匹配声音及文字的在线工具
  12. 算法题_位运算_9_出现一次的数字和出现k次的数字
  13. hdu2018 母牛的故事(模拟)
  14. Unity学习笔记:私有变量private如何在编译器可见 公有变量public在编译器隐藏
  15. 求三个数的和及平均值简单
  16. Android来电、去电监听
  17. 支持苹果IPV6 ONLY 的socket 修改方法
  18. 计算机php学习,php学习计划流程_IT/计算机_专业资料
  19. #【精华】转换大写人民币
  20. DDR扫盲——DDR的发展简史

热门文章

  1. 不同scheam下查询视图报错ORA-01031的故障解决
  2. AI洞观 | 周鸿祎秀小猪佩奇手表背后 看看360的AI战略
  3. linux自动生成证书,Linux生成TLS证书
  4. 有哪些值得关注的技术博客
  5. 父亲节python代码半个心_2019父亲节感恩父亲的话 父亲节对爸爸说的暖心话句子...
  6. 地质灾害监测的主要内容
  7. cesium and three.js
  8. 二叉树的高度和深度的理解
  9. 网络验证 api.php,青柠网络验证webapi接口说明
  10. 【问题4】:kaggle练习题《自行车租赁业务预测》--带数据分析,用了随机森林,支持向量机,岭回归等