Linux字符设备驱动——初体验
原创
©著作权归作者所有:来自51CTO博客作者阿基米东Archimedong的原创作品,请联系作者获取转载授权,否则将追究法律责任
以下是一个非常简单的Linux字符设备驱动 *^_^*
【驱动程序myChrDrv.c】
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
static int myChrDrv_open(struct inode *inod, struct file *fp)
{
printk(KERN_INFO "myChrDrv_open()\n");
return 0;
}
static int myChrDrv_close(struct inode *inod, struct file *fp)
{
printk(KERN_INFO "myChrDrv_close()\n");
return 0;
}
static struct file_operations fops = {
.open = myChrDrv_open,
.release = myChrDrv_close,
};
static int __init myChrDrv_init(void)
{
printk(KERN_INFO "myChrDrv_init()\n");
int ret;
// 创建并向内核注册字符设备simple_chrdev
ret = register_chrdev(250, "simple_chrdev", &fops);
return 0;
}
static void __exit myChrDrv_exit(void)
{
printk(KERN_INFO "myChrDrv_exit()\n");
unregister_chrdev(250, "simple_chrdev");
}
module_init(myChrDrv_init);
module_exit(myChrDrv_exit);
MODULE_LICENSE("Dual BSD/GPL");
【驱动程序Makefile】
obj-m += myChrDrv.o
#CROSS_COMPILE = /usr/local/arm/arm-2010.09/bin/arm-none-linux-gnueabi-
#CC = $(CROSS_COMPILE)gcc
#KDIR := /home/walle/arm/arm_os/kernel/linux-3.10.10
KDIR := /lib/modules/`uname -r`/build
default:
$(MAKE) -C $(KDIR) M=`pwd` modules
clean:
$(MAKE) -C $(KDIR) M=`pwd`
【应用程序app.c】
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd;
fd = open("/dev/simple_chrdev", O_RDWR);
if(fd < 0){
printf("open /dev/simple_chrdev failed.\n");
return -1;
}
printf("open /dev/simple_chrdev successed.\n");
close(fd);
return 0;
}
执行命令 make,编译生成驱动模块 myChrDrv.ko。
执行命令 insmod myChrDrv.ko,加载驱动模块。
执行命令 lsmod,确认模块加载成功,输出如下:
Module Size Used by
myChrDrv 12478 0
或执行命令 cat /proc/modules | grep myChrDrv,输出如下:
myChrDrv 12478 0 - Live 0xf8d28000 (O)
执行命令 dmesg | tail,查看模块初始化打印信息,输出如下:
[850978.514035] myChrDrv_init()
执行命令 gcc app.c -o app,编译生成应用程序 app。
执行命令 ./app,运行 app,出错:
虽然驱动程序初始化函数中有“register_chrdev(250, “simple_chrdev”, &fops);”,函数 register_chrdev 的作用是申请主设备号250、绑定操作相关函数 fops、向内核注册设备名为 simple_chrdev 的设备。显然此时系统中并不存在 /dev/simple_chrdev,因此需要执行命令“mknod /dev/simple_chrdev c 250 0”手动创建该设备节点。
mknod 的格式是:mknod [OPTION]… NAME TYPE [MAJOR MINOR]。命令中的“c”表示字符设备;“250”是主设备号,与驱动程序中手动申请的主设备号一致;“0”是次设备号,这里也可以不设为0,只需要主设备号对应得上就行,因为主设备号指定的是驱动,次设备号指定的是具体设备。
另外文件“/dev/simple_chrdev”要与 app.c 中 open 函数打开的文件一致,所以如果 open 指定的文件是“hello”,mknod 命令创建“hello”即可。这里之所以用“/dev/simple_chrdev”主要是为了让它看起来像一个设备。
OK,我们执行命令 ls -l /dev/simple_chrdev,确认设备节点创建成功,输出如下:
crw-r--r-- 1 root root 250, 0 5月 18 22:34 /dev/simple_chrdev
再次执行命令 ./app,运行 app,成功:
执行命令 dmesg | tail,查看驱动程序打印信息,输出如下:
[854089.294682] myChrDrv_open()
[854089.294855] myChrDrv_close()
可以看到,应用程序 app 的 open 和 close 函数最终调用了驱动程序 myChrDrv 的 open 和 release 函数。
执行命令 rmmod myChrDrv,卸载 myChrDrv 驱动。
执行命令 dmesg | tail,查看驱动程序打印信息,输出如下:
[854555.685634] myChrDrv_exit()
执行命令 rm /dev/simple_chrdev,移除设备节点。
Linux字符设备驱动的初体验完毕 *>_<*