字符设备注册流程
创建设备节点
使用mknod,格式:
mknod 名称 类型 主设备号 次设备号
eg:
mknod /dev/test c 247 0
编写模块代码(.ko文件)
模块代码可生成.ko代码,优点是insmod方便,临时的模块,适合咱们测试学习
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("monkey");
static ssize_t monkeyRead(struct file *, char *, size_t, loff_t*);
static ssize_t monkeyWrite(struct file *, const char *, size_t, loff_t*);
#define DEV_NAME "monkey_cdev"
static int char_major = 0;
static int monkeyData = 0;
struct file_operations monkeycdev_fops =
{
.read = monkeyRead,
.write = monkeyWrite
};
static int __init monkeycdev_init(void)
{
int ret;
ret = register_chrdev(char_major, DEV_NAME, &monkeycdev_fops);
if (ret<0)
{
printk(KERN_INFO "Fail!\n");
}
else
{
printk(KERN_INFO "Success!\n");
char_major = ret;
printk(KERN_INFO "Major = %d\n", char_major);
}
return ret;
}
/* 模块卸载函数 执行rmmod命令时候执行这个函数 */
static void __exit monkeycdev_exit(void)
{
unregister_chrdev(char_major, DEV_NAME); // 注销设备驱动
return;
}
/* 设备驱动读函数 */
static ssize_t monkeyRead(struct file *filp, char *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "read ok\n");
return ;
}
/* 设备驱动写函数 */
static ssize_t monkeyWrite(struct file *filp, const char *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Write ok");
return ;
}
module_init(monkeycdev_init);
module_exit(monkeycdev_exit);
编写makefile
make后生成的.ko文件就是咱们的模块代码了.首先需要知道:
obj-m = *.o
obj-y = *.o
上面两者的区别在于,前者才会生成ko文件,后者只是代码编译进内核,并不生成ko文件。
生成KO文件,分两种情况:单个.c文件和多个.c文件
1.单个.c文件
kernel配置文件中定义
CONFIG_RUNYEE_CAMVIB=m
注意上面的m,表示作为一个模块进行编译,最后在MAKEFILE中需要用到的编译开关。
然后再相应的源码目录中的MAKEFILE中添加如下语句:
obj-$(CONFIG_RUNYEE_CAMVIB) := 字符设备注册例程.o
上面的一行的作用就是编译字符设备注册例程.c的源文件,同时会生成相应的字符设备注册例程.ko文件,和编译生成的字符设备注册例程.o在同一目录,最后就是insmod动作了:
insmod /system/lib/modules/字符设备注册例程.ko
2.多个.c文件生成ko文件
kernel配置文件中定义
CONFIG_TOUCHSCREEN_FOCALTECH=m
注意上面的m,表示作为一个模块进行编译,最后在MAKEFILE中需要用到的编译开关。
然后再相应的源码目录中的MAKEFILE中添加如下语句:
obj-$(CONFIG_TOUCHSCREEN_FOCALTECH) += focaltech_ts.o
字符设备注册例程_ts-objs := 字符设备注册例程.o
字符设备注册例程_ts-objs += 字符设备注册例程1.o
字符设备注册例程_ts-objs += 字符设备注册例程2.o
上面的意思就是编译生成ko文件需要三个.c文件【字符设备注册例程.c 字符设备注册例程1.c 字符设备注册例程2.c】,最后
生成名为字符设备注册例程_ts的ko文件,注意ko文件名一定不能为字符设备注册例程。那么在obj-m和lpc-objs中都含有字符设备注册例程.o,
对make来讲会产生循环和混淆,因此也不能这样书写
最后就是insmod动作了:
insmod /system/lib/modules/字符设备注册例程_ts.ko
然后上代码:
obj-m += 字符设备注册例程.o
#ubuntu的内核源码树,如果要编译在ubuntu中安装的模块就打开这2个
KERN_VER = $(shell uname -r)
KERN_DIR = /lib/modules/$(KERN_VER)/build
all:
make -C $(KERN_DIR) M=`pwd` modules
.PHONY: clean
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
现在我们可以透过设备节点的方式去cat,也可以通过例程去查看咱们的驱动是否成功
现在提供个例程:
/* GlobalCharTest.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define DEV_NAME "/dev/monkey_cdev"
int main()
{
int fd, num;
/* 打开设备文件 */
fd = open(DEV_NAME, O_RDWR, S_IRUSR | S_IWUSR);
if (fd<0) {
printf("Open Deivec Fail!\n");
return -1;
}
/* 读取当前设备数值 */
read(fd, &num, sizeof(int));
printf("The monkey_cdev is %d\n", num);
printf("Please input a number written to monkey_cdev: ");
scanf("%d", &num);
/* 写入新的数值 */
write(fd, &num, sizeof(int));
/* 重新读取设备数值 */
read(fd, &num, sizeof(int));
printf("The monkey_cdev is %d\n", num);
close(fd);
return 0;
}
gcc这个例程,执行生成的可执行文件,就能够查看到相关信息了
是不是恍然大悟了