秒字符设备

 

使用内核定时器的秒字符设备

                                         秒字符设备

      秒字符设备也是字符驱动,所以与之前的字符设备驱动程序的框架类似,模块编译,模块加载与卸载也与内核模块的编译,加载卸载一致。秒字符设备驱(second)的实现,创建目录(second),在该目录下创建设备文件(second.c),内容按下面的代码写即可,在同一目录下编写相应的Makefile文件,然后make就可以编译模块了,然后插入模块(可以带参数,如:sudo insmod second.ko second_major=249),设备驱动程序就好了,但是现在在/dev中并没有”second”这个字符设备驱动,必须创建设备节点才行,创建设备节点的命令是:mknod /dev/chardev0 c 250 0其中chardev0是设备名,c说明设备是字符设备,250是主设备号,0是次设备号,这些都要根据自己的设备驱动程序来赋予相应的值(此处为:mknod /dev/second c 249 0)。设备节点创建成功后在/dev中就可以看到自己创建的设备了或者使用ls-l second(设备名)来查看详细信息。

秒字符设备驱动实现后要进行测试,创建测试文件(test.c)内容按下面的代码写即可。然后编译运行测试文件,就可以看到效果了。

秒字符设备(second.c)源码:

#include<linux/module.h>
#include<linux/types.h>
#include<linux/fs.h>
#include<linux/errno.h>
#include<linux/mm.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<asm/io.h>
#include<asm/system.h>
#include<asm/uaccess.h>
 
#define SECOND_MAJOR 249//宏定义主设备号
static int second_major =SECOND_MAJOR; //模块参数,可以输入主设备号
 
struct second_dev//second设备结构体
{
struct cdev cdev;//cdev结构体
atomic_t counter;//一共经历的秒数
struct timer_list s_timer;//设备要使用的定时器
};
 
struct second_dev*second_devp; //设备结构体指针
 
//定时器处理函数
static void second_timer_handle(unsigned long arg)
{
mod_timer(&second_devp->s_timer,jiffies+HZ);
atomic_inc(&second_devp->counter);//counter加1
printk(KERN_NOTICE "currentjiffies is %ld \n",jiffies);
}
 
//文件打开
int second_open(struct inode*inode,struct file *filp)
{
//初始化定时器
init_timer(&second_devp->s_timer);
second_devp->s_timer.function=&second_timer_handle;
second_devp->s_timer.expires=jiffies+HZ;
 
add_timer(&second_devp->s_timer);//注册定时器
 
atomic_set(&second_devp->counter,0);//设置counter初值为0
return 0;
}
 
//文件释放
int second_release(struct inode *inode,struct file *filp)
{
del_timer(&second_devp->s_timer);//释放定时器
 
return 0;
}
 
//读函数
static ssize_t second_read(struct file *filp,char __user *buf,size_t count,loff_t*ppos)
{
int counter;
 
counter=atomic_read(&second_devp->counter);//获得counter 的当前值
if(put_user(counter,(int*)buf)) //由于内核空间和用户空间不能直接互访,所以用put_user函数将counter的值从内核复制到用户buf所指的空间。
return -EFAULT;
else
return sizeof(unsigned int);
}
 
//文件操作结构体
static const struct file_operations second_fops =
{
.owner=THIS_MODULE,
.open=second_open,
.release=second_release,
.read=second_read
};
 
//初始化并注册cdev
static void second_setup_cdev(struct second_dev *dev,int index)
{
int err,devno=MKDEV(second_major,index); //获得主设备号
cdev_init(&dev->cdev,&second_fops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&second_fops;
err=cdev_add(&dev->cdev,devno,1);//注册设备号
if(err)
printk(KERN_NOTICE "error %dadding led %d",err,index);
}
 
//模块加载函数
int second_init(void)
{
int ret;
dev_t devno=MKDEV(second_major,0);
 
if(second_major)
ret=register_chrdev_region(devno,1,"second");//申请设备号
else
{
ret=alloc_chrdev_region(&devno,0,1,"second");//动态申请设备号
second_major=MAJOR(devno);//获得申请到的设备号
}
if(ret<0)
return ret;
//动态申请设备结构体的内存
second_devp=kmalloc(sizeof(struct second_dev),GFP_KERNEL);
if(!second_devp)//申请失败
{
ret = -ENOMEM;
goto fail_malloc;
}
 
//设置second_devp所指的大小为sizeof(strcutsecond_dev)的内存均为0
memset(second_devp,0,sizeof(struct second_dev));
second_setup_cdev(second_devp,0);//初始化并注册cdev
return 0;
fail_malloc:unregister_chrdev_region(devno,1);
}
 
//模块卸载函数
void second_exit(void)
{
cdev_del(&second_devp->cdev);//注销cdev
kfree(second_devp);//释放设备结构体内存
unregister_chrdev_region(MKDEV(second_major,0),1);//释放设备号
}
 
MODULE_AUTHOR("w");
MODULE_LICENSE("GPL");
 
module_param(second_major,int,S_IRUGO);
 
module_init(second_init);
module_exit(second_exit);

Makefile文件源码:

obj-m := second.o
path =/usr/src/linux-headers-$(shell uname -r)
all:
make -C $(path) M=$(PWD)modules
clean:
make -C $(path) M=$(PWD)clean

测试文件(test.c)源码:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
 
int main()
{
int fd;
int counter=0;
int old_counter=0;
fd=open("/dev/second",O_RDONLY); //打开设备文件
if(fd!=-1)
{
while(1)
{
read(fd,&counter,sizeof(unsigned int ));//读目前经历的秒数
if(counter!=old_counter)
{
printf("seconds after open/dev/second:%d\n",counter);
old_counter=counter;
}
}
}
else
printf("device openfail\n");
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值