博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
驱动函数(1)
阅读量:4297 次
发布时间:2019-05-27

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

话说,从事嵌入式或者相关开发的,最难搞的就是驱动了,其实说实在的,做任何的事情都不是那么的简单,你得到的回报大都是小于等于你相应的能力的,个别幸运的就不说了,所以只有学会大都都不会的,你才能脱颖而出,获得更大的价值。

仔细的想下,很多人很是迷茫的做着自己的事情,甚至干了很长的时间,也没有真正的认清楚自己到底为什么这样做,以及这样做的目的,何为驱动,简单的概括,就是为了给上层提供一个统一的接口,我们都知道在上层有很多的函数,都是通用的,你可以随便的使用,但是函数名字都是一样的,这是因为如果不这样做的话,估计全世界都乱套了,这是这个行业的规范(GPL),那么针对不同的开发平台,虽然上面是一样的,但是下面肯定是不一样的,这就是我们驱动工程师的事情了,我们要为上层服务。

所以对驱动工程师的要求一般很多,既要了解整个平台的架构,又要理解底层的相关硬件的原理,上层的话,你要知道整个应用层的具体实现,这样拿到高的回报也就理所当然啦。

最近一直涉及驱动方面的学习还谈不上研究,在我看来,相对于应用层的千变万化来说,驱动层很少变化,很多都是相似的开发套路,下面结合最近所学,介绍几个经常使用到的函数,以及关于驱动的相关知识,希望对正在从事本行业的友人,提供点滴参考,当然,如果哪里写的不是很恰当,欢迎批评指出。

1. 初始化设备cdev结构体函数

void cdev_init(struct cdev * cdev,const struct file_operations * fops)

函数功能: 初始化cdev  结构体

参数:

cdev  : cdev 结构体

fops  : 操作函数的结构体

2. 申请设备号的函数

Int  register_chrdev_region(dev_t from ,unsigned count ,const char * name)

功能: 申请设备的设备号

参数:

from    : 包含主设备号的数字

count  : 设备号的个数

name : 设备号的名字,注意,我们可以在/proc/devices中看到我们所设置的名字

成功返回 0 ,失败返回负的错误码

3. 添加字符设备函数

int  cdev_add(struct  cdev * p,dev_t dev,unsigned count);

参数:

p        : cdev结构体

dev    : 第一个设备号

count : 次设备号的个数

成功返回0 ,失败返回负的错误码

4. 动态注册设备号的函数

int alloc_chrdev_region(dev_t  * dev , unsigned baseminor ,unsigned count,const char * name)

参数:

dev             :  获得的设备号

baseminor : 第一个次设备号

count          :  次设备号的个数

name          : 设备号的名字

成功返回0 ,失败返回负的错误码

5. 通过主 次设备生成设备号的宏

MKDEV( major,  minor)

参数:

major:主设备号

minor:次设备号

6. 通过设备号,获得主设备号,或次设备号

获得主设备号的宏:MAJOR(dev_num)          获得设备号的前12位

获得此设备号的宏:MINOR (dev_num)            获得设备号的后20位

7.如何在添加驱动的时候自动生成设备节点

1》创建类  在/sys/class目录下创建一个子目录

struct  class * class_create(struct module *owner ,char *name)

参数:

owner : 这个是固定死了的,THIS_MODULE

name: 子目录的名字

成功返回有效的指针,失败返回负的错误码

2》 在sysfs文件中注册设备(导出主设备号和次设备号)

struct device * device_create(struct class *class ,struct device *parent, dev_t  devt,void *drvdata, const  char *fmt,...)

参数:

class: 类结构体的首地址

parent: NULL

devt : 设备号

drvdata:NULL

fmt: 格式化字符串 "mycdev"   or   "mycdev_%d",i

成功返回有效指针,失败返回负的错误码

8.那么,我们如何判断是有效的指针还是负的错误码呢?

提供了一个宏:

IS_ERR(指针)                                          PRT_ERR(指针)

返回值:若是负的错误码返回真   返回负的错误码

9. 用户空间和驱动程序数据之间的交互

long copy_to_user(void __user *to,const void *from,unsigned long n)

函数功能: 将内和空间的数据拷贝到用户空间,这里边需要注意的是,__user只是一个空的宏定义,为的就是标记用户空间

参数:

to :用户空间的地址

from: 内核空间的地址

n : 大小

成功返回0 , 失败返回未拷贝的数据大小

10. long copy_from_user(void *to ,const void __user from,unsigned long n)

参数 :

to : 内核空间的地址

from :用户空间的地址

n: 大小

成功返回0 ,失败返回未拷贝的数据的大小

11 .单个数据拷贝

宏: put_user(value , ptr)

功能:将value写到ptr指向的地址(用户)

宏: get_user(value,ptr)

功能: 将ptr指向的地址(用户)内容读到value

12.可以通过一些命令来控制的函数ioctl

这里面需要注意的,就是内核版本的不同,所使用的函数的名字是不同的

在2.6内核以及之前使用的是:

int  (*ioctl )(struct inode *inode ,struct file* file,unsigned int cmd,unsigned long arg);

而在2.6版本之后使用的是:

long (*unlocked_ioctl)(struct file * file,unsigned int cmd,unsigned long arg);

参数:

cmd:传递的命令,通常就是一些宏定义之类的

arg :传递的参数(包括数值或地址)如果是地址值的话,这个地址是用户空间的,可以用put_user,or get_user来操作

13.另外,我们如果要对哪个GPIO口来进行操作的话,我们还要去查我们的用户手册,但是从手册上面我们得到的地址是实际的物理地址,而我们的操作系统使用的是虚拟的地址,那么这个时候,我们就需要将实际的物理地址做一个映射,映射为虚拟地址。

void *ioremap(unsigned long phy_addr,int size)

功能:将物理地址与虚拟地址进行映射

参数:

phy_addr: 物理地址

size    : 映射的大小

14. 有些时候我们需要从一个很长的地址中取出那些我们需要的位,这个时候,就需要使用下面的这两个函数了

1》static inline u32 readl(const volatile void _iomem * addr)

{  return *(const valatile u32 __force *) addr;    }

函数功能:从一个地址中读取四个字节

2》static inline void writel(u32 b, volatile void _iomem * addr)

{ (volatile u32 _force *)addr = b; }

函数功能:向一个地址中写四个字节

未完待续... ...

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

你可能感兴趣的文章
重启小狼毫输入法,rime输入法重启
查看>>
命令行或终端ImportError:No module named(pycharm运行没问题)
查看>>
量化策略回测01双均线
查看>>
量化策略回测ATRRSI
查看>>
量化干货:量化交易系统设计的六大细节
查看>>
量化策略回测tdma
查看>>
量化策略回测TRIXKDJ
查看>>
量化策略回测唐安奇通道
查看>>
CTA策略如何过滤部分震荡行情?
查看>>
量化策略回测DualThrust
查看>>
量化策略回测BoolC
查看>>
量化策略回测DCCV2
查看>>
mongodb查询优化
查看>>
五步git操作搞定Github中fork的项目与原作者同步
查看>>
git 删除远程分支
查看>>
删远端分支报错remote refs do not exist或git: refusing to delete the current branch解决方法
查看>>
python multiprocessing遇到Can’t pickle instancemethod问题
查看>>
APP真机测试及发布
查看>>
iOS学习之 plist文件的读写
查看>>
通知机制 (Notifications)
查看>>