Linux设备中最大的特点就是设备操作犹如文件操作一般,在应用层看来,硬件设备只是一个设备文件。应用程序可以像操作文件一样对硬件设备进行操作,如open(),close(),read(),write()等。
下面是一个字符设备驱动程序的简单实现test.c
模块分析
1.初始化设备驱动的结构体
struct file_operations test_fops = {
.owner=THIS_MODULE,
.read=read_test,
.write=write_test,
.open=open_test,
.release=release_test,
};
定义了设备IO时所调用的函数,实际上在该模块中,上层read调用的就是底层的read_test,write调用write_test,open调用open_test,close调用release_test 。
2.module_init函数
int simple_c_init_module(void)
{
int result;
dev_t dev = 0;
dev=MKDEV(test_major,test_minor);
result = register_chrdev_region(dev,1,"test");
printk("major= %d,minor=%d /n",test_major,test_minor);
if(result < 0)
{
printk(KERN_INFO "test : can't get major number/n");
return result;
}
cdev_init(&cdevc,&test_fops);
cdevc.owner= THIS_MODULE;
cdevc.ops=&test_fops;
result=cdev_add(&cdevc,dev,1);
if(result)
printk("Error %d adding test",result);
return 0;
}
(1)首先MKDEV一个设备,test_major和test_minor分别定义在文件的前面
unsigned int test_major=253;
unsigned int test_minor=0;
(2)然后注册一个范围内的设备编号,
result = register_chrdev_region(dev,1,"test");
该函数原型是
三个参数分别表示:第一次在预期的范围内的设备编号,连续数的装置所需数量,这个名字的设备或驱动程序。
(3)printk在内核中类似printf函数,打印出两个设备号。
(4)初始化字符设备结构体cdev_init(&cdevc,&test_fops);
两个参数分别表示:这个结构的初始化,本设备的file_operations,
函数的功能是:记住fops cdev初始化,使之可以添加到系统和cdev_add。
(5)为字符设备的结构cdevc赋值
(6)调用int cdev_add ( struct cdev *p, dev_t dev, unsigned count);
作用:cdev_add 将p结构体加入到系统的设备,使其立即生效。 一个负的错误代码返回失败。
3.module_exit();函数
void simple_c_cleanup_module(void)
{
dev_t dev=0;
dev = MKDEV(test_major,test_minor);
cdev_del(&cdevc);
unregister_chrdev_region(dev,1);
}
函数 cdev_del —从系统中移除一个字符设备
函数 unregister_chrdev_region 返回的设备数字范围
4.底层函数设计
演示:
编译,make(Makefile参见http://blog.csdn.net/wanxiao009/archive/2010/06/13/5669665.aspx)
生成test.ko
minicom登录开发板,
发送到开发板中,
chmod +x test.ko
创建设备节点 mknod /dev/test c 253 0(253 0 就是test_major,test_minor)
insmod test.ko
如下图所示
说明字符驱动可以成功添加到内核模块中 ^_^!