现在的位置: 首页Linux&Android>正文
linux字符型设备(chrdev)驱动初步分析
2012年02月10日 Linux&Android 暂无评论

本文简略地分析总结了一下linux的字符型设备驱动编写流程,以满足一些简单的驱动编写,如驱动硬件IO等操作.
除了要包含的那一堆头文件外,linux的字符型驱动主要程序实际上只有两个接口:

1
2
module_init(mydev_init);
module_exit(mydev_exit);

module_init与module_ext分别用来指明内核在初始化与卸载驱动时所指向的函数入口. 在指明了函数入口后,就须要编写这两个函数的具估内容了.

首先:拿mydev_init来说:

1
2
3
4
5
6
7
static int __init mydev_init(void);
{
int ret;
some_codes();
ret=register_chrdev(XXX_MAJOR,DEVICE_NAME,&XXX_fops);
some_codes();
}

其中mydev_init的函数格式为固定的static int __init mydev_init(void);

整个函数里最重要的一步当然是ret=register_chrdev(XXX_MAJOR,DEVICE_NAME,&XXX_fops);

作 用是向内核注册一个字符型设备驱动,其中第一个参数为主设备号(如果为0表示由系统分配),第二个为驱动名称(将会在/dev目录下升成这个文件),第三 个参数为file_operations结构函数地址.我们要做的工作就是去完成file_operations这个结构体里的各个成员,它们完成与应用 程序的沟通.

在file_operations结构体中有非常多的成员,我们只须要完成我们关心的部份即可,不须要完全是实现它.以下是一个适用于s3c2440控制IO的一个演示示例,这里我们假定GPG4上接有一个LED,我们的目的就是驱动它的亮灭:

1.创建文件csmekdev.c放到内核源码目录/drivers/char.内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <linux/errno.h> 
#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/slab.h> 
#include <linux/input.h> 
#include <linux/init.h> 
#include <linux/serio.h> 
#include <linux/delay.h> 
#include <linux/clk.h> 
#include <linux/miscdevice.h> 
#include <linux/gpio.h> 
 
#include <asm/io.h> 
#include <asm/irq.h> 
#include <asm/uaccess.h> 
#include <mach/regs-clock.h> 
#include <plat/regs-timer.h> 
 
#include <mach/regs-gpio.h> 
#include <linux/cdev.h> 
 
#include <linux/fs.h>
 
 
#define DEVICE_NAME     "csmekdev"  	//设备名csmekdev
#define CSMEKDEV_MAJOR 220      		//主设备号220
 
static int csmekdev_ioctl(struct inode *inode,struct file *file,
							unsigned int cmd,unsigned long arg)
{
s3c2410_gpio_setpin(S3C2410_GPG(4), cmd);
}
 
 
static ssize_t dev_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) 
{ 
 unsigned char stats; 
 int ret; 
 if (count == 0) { 
 return count; 
 } 
 ret = copy_from_user(&stats, buffer, sizeof stats) ? -EFAULT : 0; 
 if (ret) { 
  return ret; 
 } 
 
    stats &= 0x01;
	s3c2410_gpio_setpin(S3C2410_GPG(4),stats);
 
 return count; 
} 
 
 
 
 
static struct file_operations csmekdev_fops = {
	.owner    =     THIS_MODULE,
    .ioctl    =     csmekdev_ioctl,
	.write	  =		dev_write, 
};
 
 
static int __init csmekdev_module_init(void)
{
	int ret;
	int i;
	ret = register_chrdev(CSMEKDEV_MAJOR, DEVICE_NAME, &csmekdev_fops);
	if (ret < 0) {
		printk(DEVICE_NAME " can't register major number\n");
		return ret;
       }
	s3c2410_gpio_cfgpin(S3C2410_GPG(4), S3C2410_GPIO_OUTPUT);
/*	s3c2410_gpio_setpin(S3C2410_GPG4, 0);    */
	printk(DEVICE_NAME " initialized\n");
	return 0;
} 
 
static void __exit csmekdev_module_exit(void)
{
	unregister_chrdev(CSMEKDEV_MAJOR, DEVICE_NAME);
	printk(DEVICE_NAME " removed\n");
} 
 
module_init(csmekdev_module_init);
module_exit(csmekdev_module_exit);
2.然后修改Kconfig在文件最后加入
1
2
config CSMEKDEV_SMDK2440
tristate &quot;CsmekDev on SMDK2440&quot;

[MEDIUM]3.再修改makefile加入:[/MEDIUM]

"obj-$(CONFIG_CSMEKDEV_SMDK2440) += csmekdev.o"

然后menuconfig时,在 Device Drivers->Character devices中,将CsmekDev on SMDK2440编译进内核(即选择为* 不能是选择为M).然后编译,烧录.在开发板上运行"cat /proc/devices"可以看到我们的驱动已经注册到内核,如下图:

http--csmek.com-images-article-201110-proc

然后我们建立设备文件:"mknod /dev/csmekdev c 220 0".

这 样就会在/dev目录下建立一个csmekdev的文件.我们对这个文件的操作就可完成一些动作比如: "echo 0 > /dev/csmekdev" 即GPG4置低,"echo 1 > /dev/csmekdev"置高GPIO,也可以使用IOCTL的方式,只需要我们去完善csmekdev_fops结构体成员.

文章来源:http://csmek.com/technical/item/linux-chrdev-driver-analyze



给我留言

留言无头像?


无觅相关文章插件,快速提升流量