一.编译安装字符设备驱动模块
1.要有Makefile
obj-m := memdev.o
KDIR := /ok6410/linux-3.10
all:
make -C $(KDIR)M=(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
2.要有合适的驱动文件
3.insmod lsmod rmmod命令使用。
二.安装字符设备(节点)文件
1.应用程序通过文件名找到设备文件
2.设备文件通过主设备号找到与之匹配的驱动程序。(设备文件和驱动程序都有主设备号,相同则匹配)
3.可以通过cat /proc/devices打印驱动程序信息(主要是主设备号,次设备号0-255都可以)
4.创建方法
mknod /dev/设备文件名 c 主设备号 次设备号(主设备号和驱动程序要一致)
5.这里的字符设备是虚拟的设备,用一段内存(比如说一个数组)模拟硬件的几个寄存器
6.遇到not found有可能是依赖关系不满足,利用arm-linux-readelf -d 文件名来查看该程序所需要的动态链接库。从而进一步解决问题。
三.写数据程序
四.读数据应用程序
五.开发板操作
六.字符设备描述结构
1.在任何一种驱动模型中,设备都会采用内核中的一种结构来描述。
2.字符设备的描述采用的是
3.通过主设备号匹配设备文件和设备驱动。区分同类型的设备用次设备号。在内核中用dev_t定义设备号,实质就是unsigned int类型。高12位主设备号,低20位次设备号。
4.将主设备号和次设备号组合成结构体中的设备号成员,用MKDEV(注设备号,次设备号)。如果要从设备号分离出主设备号和次设备号,用MAJOR(dev_t 设备号)。MINOR(dev_t 设备号)。
5.分配主设备号:
(1)静态申请--register_chrdev_region。但是有可能失败以及不能正常使用,因为有可能设备号冲突。
(2)动态分配--alloc_chrdev_region。这样不会冲突。
(3)设备号注销--unregister_chrdev_region,再不用设备以后要释放。
6.操作函数集
(1)起到映射作用,将应用空间的函数和驱动的函数通过fileoperations操作函数集对应起来
(2)不需要的设置成空指针NULL即可
七.字符设备驱动模型
1.驱动初始化:(一般在module_init中完成)
(1)分配cdev。可以静态分配(直接定义),也可以动态分配(struct cdev *pdev = cdev_alloc())。
(2)初始化cdev。cdev_init(struct cdev * pdev ,const struct file_operations *fops);
(3)注册cdev。cdev_add(struct cdev * pdev ,dev_t dev,unsigned count dev_number);
(4)硬件初始化
2.实现设备操作
(1)关于struct file
在linux系统中,每打开一个文件(要打开才会有),在内核中都会关联一个struct file文件,这是由Linux内核在打开文件的时候创建的。在文件关闭后会释放这个struct file结构体。
其中重要的成员有:
loff_t f_pos---文件读写指针
struct file_operations* f_ops----该文件所对应的操作。
(2)关于struct inod
每一个存在于文件系统的文件都会有一个inod结构体和它对应。主要是用来记录文件的物理信息。不管文件是否打开,都会关联。
重要成员
dev_t t_rdev---设备号
(3)open设备方法
为以后的工作做准备,完成初始化工作。主要是标明次设备号,启动设备
(4)release:有时候也叫做close。就是关闭设备。
(5)read:从设备中读取数据到驱动程序(内核空间),然后将读取到的数据返回给用户空间。原型如下
注意:buff参数是来源于用户空间的指针,这类指针不能被内核空间的代码直接使用,必须使用专门的函数
int copy_from_user(void* to ,const void _user *from,int n);
int copy_to_user(void _user* to,const void * from,int n );
(6)write
-->从应用程序提供的地址中读取数据
-->将数据写入设备(硬件类操作)
参数类似于read。
(7)llseek:重定位读写指针,相应系统调用。
3.驱动注销
从内核卸载驱动程序的时候,使用cdev_del函数来完成。而且要最后释放掉设备号。
八.关于应用程序使用系统调用,最终调用内核空间的驱动函数(设备方法):
1.在应用程序汇编的时候,将要调用的系统调用编号存入r7,
2.执行svc指令完成从应用空间到内核空间的跳转
3.取出系统调用编号
4.查表得到对应内核空间的实际的代码(函数)
5.通过vfs_read函数实际调用驱动函