分类: LINUX
2013-01-16 21:57:54
#include#include #include #include static struct cdev chr_dev;//定义一个字符设备对象 static dev_t ndev; //字符设备节点的设备号 static int chr_open(struct inode *nd, struct file *filp) { int major=MAJOR(nd->i_rdev); int minor=MINOR(nd->i_rdev); printk("chr_open,major=%d,minor=%d\n",major,minor); return 0; } static ssize_t chr_read(struct file *f,char __user *u,size_t sz,loff_t *off) { printf("In the chr_read() function!\n"); return 0; } //字符设备驱动程序中非常关键的一个数据结构struct file_operations struct file_operations chr_ops= { .owner=THIS_MODULE, .open =chr_open, .read =chr_read, } //模块的初始化函数 static int demo_init(void) { int ret; cdev_init(&chr_dev,&chr_ops); //初始化字符设备对象 ret=alloc_chrdev_region(&ndev,0,1,"chr_dev");//分配设备号 if(ret<0) return ret; printk("demo_init():major=%d,minor=%d\n",MAJOR(ndev),MINOR(ndev)); ret=cdev_add(&chr_dev,ndev,1);//将字符设备对象chr_dev注册进系统 if(ret<0) return ret; return 0; } static void demo_exit(void) { printk("Removing chr_dev module...\n"); cdev_del(&chr_dev);//将字符设备对象chr_dev从系统中注销掉 unregister_chrdev_region(ndev,1); //释放分配的设备号 } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dennis @AMDLinuxFGL"); MODULE_DESCRIPTION("A char device driver as an example"); obj-m :=demo_chr_dev.o KERNELDIR:=/lib/module/$(shell uname -r)/build PWD :=$(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -f *.o *.ko *.mod.c
#include#include #include #define CHR_DEV_NAME "/dev/chr_dev" int main() { int ret; char buf[32]; int fd=open(CHR_DEV_NAME,O_RDONLY|O_NDELAY); if(fd<0) { printf("open file %s failed\n",CHR_DEV_NAME); return -1; } read(fd,buf,32); close(fd); return 0; }
使用gcc来生成应用程序的可执行文件main:
gcc main.c -o main
主要是用open打开一个设备文件节点,然后在打开的设备文件描述符fd上调用read函数。
将展示应用程序如何通过文件系统调用,穿越内核空间,呼叫到设备驱动程序实现的各种接口函数。
使用insmod把demo_chr_dev.ko加入到系统:
insmod demo_chr_dev.ko
使用dmesg查看insmod的输出信息
可以看到alloc_chrdev_region函数给内核模块demo_chr_dev.ko分配的主设备号major=248,minor=0。
根据这个设备号信息用mknod命名在系统的/dev目录下为该模块生成一个新的设备文件节点:
mknod /dev/chr_dev c 248 0
ls -l /dev/chr_dev
有了对应的设备文件后,现在我们可以运行我们的应用程序了:
./main
查看dmesg对此的输出信息:
我们见证了应用程序成功调用到了设备驱动程序实现的函数。
其成员变量基本上都是函数指针
现实中字符设备驱动程序的编写,其实基本上是围绕着如何实现struct file_operations中的那些函数指针成员而展开的。