一、驱动程序测试
1、在Kconfig文件中添加相应的config xxx编译选项,在Makefile中添加obj-$(CONFIG_xxx) += xx.o
<注意上面的两个xxx是对应的,而xx需要与源文件xx.c相对应>
2、配置好后需要先编译一遍内核和dtb文件,在make modules才能正确加载模块。<至于是跟内核有关还是跟dtb文件有关就不知道了>
二、内核驱动设备号、设备类、设备节点等的操作
1、第一组组合
①、int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
自动分配设备号,成功返回0,失败返回小于0值。
②、
a、void cdev_init(struct cdev *cdev, const struct file_operations *fops)
建立cdev与file_operations 之间的连接
b、int cdev_add(struct cdev *, dev_t, unsigned)
向系统添加cdev完成设备注册
③、
a、class_create( , )
在/sys/class下创建设备类
b、device_create( , , , , )
创建设备节点
<还有一组>
④、卸载设备采取上述相反的操作即可
device_destroy() =》class_destroy() =》cdev_del() =》unregister_chrdev_region()。
删除涉设备节点 =》 删除设备类 =》注销字符设备=》注销设备号
三、申请I/O内存函数
request_mem_region(start, n, name)
release_mem_region(start, n)
四、ioctl函数
2.6.x版本后取消了ioctl(),转而用unlocked_ioctl()和compat_ioctl(),后两者区别有机会日后补充。
1、long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
①、cmd参数介绍
每一个cmd命令由一个整形数据构成(32bits),将一个命令分成四部分:设备类型(幻数)8bits,方向2bits,序号8bits,数据大小14bits。
可以使用Linux提供的宏来实现cmd命令定义:
_IO(type,nr) 表示定义一个没有方向的命令,
_IOR(type,nr,size) 表示定义一个类型为type,序号为nr,数据大小为size的读命令
_IOW(type,nr,size) 表示定义一个类型为type,序号为nr,数据大小为size的写命令
_IOWR(type,nr,size) 表示定义一个类型为type,序号为nr,数据大小为size的写读命令
例:
#define MAGIC_NUM 'k' //幻数,主要用于表示类型
#define MEMDEV_PRINTF _IO(MAGIC_NUM,1)
#define MEMDEV_READ _IOR(MAGIC_NUM,2,int)
#define MEMDEV_WRITE _IOW(MAGIC_NUM,3,int)
#define MEM_MAX_CMD 3 //最大的序列号
为什么不直接#define MEMDEV_PRINTF 1这样,因为这样遇到了错误,至于为什么还没搞清楚。。。。
解析命令的宏:
/*确定命令的方向*/
_IOC_DIR(nr)
/*确定命令的类型*/
_IOC_TYPE(nr)
/*确定命令的序号*/
_IOC_NR(nr)
/*确定命令的大小*/
_IOC_SIZE(nr)
具体参考http://blog.chinaunix.net/uid-20937170-id-3033633.html吧,感谢!
五、模块编译过程(*.mod.o文件)
编译过程经历了这样的步骤:先进入Linux内核所在的目录,并编译出hello.o文件,运行MODPOST会生成临时的hello.mod.c文件,而后根据此文件编译出hello.mod.o,之后连接hello.o和hello.mod.o文件得到模块目标文件hello.ko,最后离开Linux内核所在的目录。