Linux安装Nvidia驱动

1. 在NVIDIA官方网站下载最新的驱动,并加上可执行权限
chmod +x NVIDIA-Linux-x86-xxx.xx.run
xxx.xx为驱动的版本号

2.修改boot启动文件,添加nouveau.modeset=0.

3.重启计算机,在grub处按’e‘编辑,在’linux /boot/vmware‘行最后加上’3’,然后按’F10’启动系统进入图形界面.

4.登录系统后启动安装文件,xxx.xx为驱动的版本号.
su -c ‘./NVIDIA-Linux-x86-295.59.run’
按照提示进行安装,跟WINDOWS的’下一步’类似.

5.编辑/etc/modprobe.d/blacklist.conf文件,以阻止nouveau模块的加载.
su -c ‘vi /etc/modprobe.d/blacklist.conf’
在文件最后添加下面字符后保存退出.
blacklist nouveau

6.在终端输入cvt 1280 1024 60得到hsync、 pclk两个值,修改/etc/X11/xorg.conf,把前面得到的值分別修改HorizSynVertRefresh.

Chromium 自动更新 for Linux

Chromium 使用Shell来自动更新.
很方便,不废话直接上代码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
mkdir -p /tmp/chrome
cd /tmp/chrome
wget http://commondatastorage.googleapis.com/chromium-browser-continuous/Linux/LAST_CHANGE -O LATEST
last=`cat LATEST`
url="http://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux/${last}/chrome-linux.zip"
echo [$url]
wget http://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux/${last}/chrome-linux.zip
cd /tmp/chrome
unzip -o chrome-linux.zip
cp -r chrome-linux/* /opt/Chrome/
rm -rf *
echo "Update OK!"
echo "The version is:${last}"

天使与恶魔

无神论者
        他不信神鬼,相信了科学,程度100%。虽然不少东西他至今都解释不了,不过他依然会用任何理由说服身边的人。在我们眼里这或许是狡辩,或许是欺骗,但是他的信徒们选择了相信他,这才是重点。神与恶魔在他的身边徘徊,神引导他,恶魔引诱他,一次又一次的受着神与恶魔的驱使,无论他是否达到他的梦想,他依然会用所以得理由说服洗脑自己,让自己信服自己;于是他选择了相信地球因为拥有了宇宙所以而显得美,宇宙的存在是因为地球,即使这与他所追求的科学而违背,他依然会坚信自己。

虔诚的信徒
        他相信神,他相信恶魔,当然他也会相信他承认的科学。他从小就遵守神给予他的规矩,每天都会祈求神保佑爱护自己,并且他非常恐惧恶魔,非常害怕恶魔惩罚他,所以他不曾做过任何出格的事情。他开始教育身边的人,想让大家都知道神的力量,让大家都相信只有虔诚的祈求才会得到神的祝福,即使他自己的成功,他自己的成就,他依然会感谢神让他成功,无论神是否存在;于是他选择了相信宇地球因为宇宙的存在而变得美丽,他坚信神就居住在宇宙里,坚信宇宙的美丽,虽然宇宙并不美丽也不安全。

 

        一样的感觉宇宙很美,一样的坚信自己的道路,一样的洗脑自己,其实能洗脑的又怎么是科学与神鬼,是自己选择了相信他们,自己在给予自己理由去相信他们。狂热的追求者远离他们的追求后,或者说梦想破灭后,大多都会埋怨对方将自己洗脑,将自己拉拢进去,事实不是自己在选择着相信?无论怎么的逃避掩盖狡辩已经发生的事情,他们在旁观者眼里都是同情或者说可笑。自己选择了戴上绿帽子,自己选择了压死群众,自己选择了贪污腐败,为什么总喜欢说“身不由己”?你的身选择这样由怎么由心去控制?你的身已经脱离灵魂的存在,你的身已经放弃你,选择了虚荣、物质,你的心怎么选择已经不重要了,身总会告诉心许多的理由让心信服并服从。只不过自己是由身与心构成的,无论是心还是身,都是自己,都是自己在选择,就算想“顺其自然”,也是心与身最终的选择。心与身都在逃避的时候,或许我们就是精神分裂,神经病之类的吧,心有心的活法,身有身的活法。

        “别人笑我太疯癫,我笑别人看不穿”的活法是心妥协了身,还是身妥协了心?或者说他们分道扬镳了?不过怎么样都好,坚信心与身志同道合的时候,那件事件总会办的很好,所以自己或者的最大敌人,最大的困难时让心与身同步进行,虽然这是不可能完全的存在。

Linux设备驱动(五)–系统时钟与定时器

时钟脉冲:脉冲信号是一个按一定电压幅度,一定时间间隔连续发出的脉冲信号,脉冲信号之间的时间间隔称为周期。
时钟频率:在单位时间(如1秒)内产生的时钟脉冲个数。
频率的其相应的单位有:Hz(赫)、kHz(千赫)、MHz(兆赫)、GHz(吉赫);其中1GHz=1000MHz,1MHz=1000kHz.1kHz=1000Hz。

s3c2440有外部晶振XTIPLL和外部时钟频率EXTCLK.并有两个PLL(锁相环):MPLL和UPLL.
UPLL:USB设备专用

  • UCLK:USB设备的时钟频率

MPLL:用于CPU和其他外围设备,MPLL会产生3个部分的时钟频率:FCLK、HCLK、PCLK

  • FCLK:用于CPU核
  • HCLK:用于高速总线设备
  • PCLK:用于低速总线设备

下图为PLL设置流程图:

LOCKTIME寄存器设置Lock Time所需的时间

MPLLCON寄存器设置FCLK和Fin(时钟源频率)的倍数
通过MPLLCON寄存器设置MDIV、PDIV、SDIV三个值得到FCLK与Fin的倍率
FCLK和Fin的计算公式:

MPLL(FCLK)= (2*m*Fin)/(p*2^s)
m=MDIV+8 p=PDIV+2 s=SDIV

CLKDIVN寄存器设置FCLK、HCLK、PCLK三者的比例

定时器输出时钟频率=PCLK/{prescaler value+ 1}/{divider value}
{prescaler value+ 1} = 0 ~ 255
prescaler value=TCFG0
{divider value} = 2 , 4 , 8 , 16
divider value=TCFG1

TCON:设置装载定时器计数值,并启动定时器.

定时器内部控制逻辑的工作流程:
①初始化或者获取PCLK值。
②程序初始,设置TCMPBn、TCNTBn这两个寄存器,它们表示定时器n的比较值、初始计数值。
③随之设置TCON寄存器启动定时器n,这时,TCMPBn、TCNTBn的值将被装入其内部寄存器TCMPn、TCNTn中。在定时器n的工作频率下,TCNTn开始减一计数,其值可以通过读取TCNTOn寄存器得知。
④当TCNTn的值等于TCMPn的值时,定时器n的输出管脚TOUTn反转;TCNTn继续减一计数。
⑤当TCNTn的值到达0时,其输出管脚TOUTn再次反转,并触发定时器n的中断。
⑥当TCNTn的值到达0时,如果在TCON寄存器中将定时器n设为“自动加载”,则TCMPB0和TCNTB0寄存器的值被自动装入TCMP0和TCNT0寄存器中,下一个计数流程开始。
定时器n的输出管脚TOUTn初始状态为高电平,以后在TCNTn的值等于TCMPn的值、TCNTn的值等于0时反转。

下图为详细的工作流程图:

最后通过例子结合芯片手册的定时器设置章节理解:

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
 
#define DEVICE_NAME "motor"
 
#define Age_Life	10
#define Back_Life	110
#define Car_Stop	00
 
static struct cdev *motor_cdev;
static dev_t devno;
static struct semaphore lock;
 
 
static void Motor_Ferg(unsigned long freq,unsigned int direction)
{
	unsigned long tcon;
	unsigned long tcnt;
	unsigned long tcfg1;
	unsigned long tcfg0;
 
	struct clk *clk_p;
	unsigned long pclk;
 
        /*设置GPH10为OUTPUT模式*/
	s3c2410_gpio_cfgpin(S3C2410_GPH(10),S3C2410_GPIO_OUTPUT);
	/*设置GPH10的转向,由direction控制方向*/
	s3c2410_gpio_setpin(S3C2410_GPH(10),direction);
	/*设置GPB1为定时器1模式*/
	s3c2410_gpio_cfgpin(S3C2410_GPB(1),S3C2410_GPB1_TOUT1);
 
        /*读取TCON、TCFG1、TCFG0三个寄存器的值*/
	tcon	= __raw_readl(S3C2410_TCON);
	tcfg1	= __raw_readl(S3C2410_TCFG1);
	tcfg0	= __raw_readl(S3C2410_TCFG0);
 
        /*定时器0和1的预分频值的掩码*/
	tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
	/*设置预分频率为50赫兹*/
	tcfg0 |=  (50-1);
 
        /*定时器定1分频值的掩码*/
	tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK;
	/*设置定时器1为16分频*/
	tcfg1 |= S3C2410_TCFG1_MUX1_DIV16;
 
        /*将设置好的分频值写入寄存器TCFG0和TCFG1当中*/
	__raw_writel(tcfg1, S3C2410_TCFG1);
        __raw_writel(tcfg0, S3C2410_TCFG0);
 
        /*获取PCLK值*/
	clk_p = clk_get(NULL,"pclk");
	pclk  = clk_get_rate(clk_p);
 
        /*得到定时器的输入时钟,进而设置PWM的调制频率*/
	tcnt  = (pclk/50/16)/freq;
 
        /*设置TCNTB1和TCMPB1的值并写入寄存器*/
	__raw_writel(tcnt, S3C2410_TCNTB(1));
        __raw_writel(tcnt/2, S3C2410_TCMPB(1));
 
        /*设置定时器1启动,装载TCNTB1和TCMPB1并自动重载模式*/
	tcon &= ~0xff0;
	tcon |= 0xb00;
 
        /*写入寄存器TCON*/
	__raw_writel(tcon,S3C2410_TCON);
 
        /*设置TCNTB1和TCMPB1的值手动更新并写入寄存器*/
	tcon &= ~0x600;
	__raw_writel(tcon,S3C2410_TCON);
}
 
/*停止运作函数*/
static void Motor_Stop(void)
{
	s3c2410_gpio_cfgpin(S3C2410_GPB(1),S3C2410_GPIO_OUTPUT);
	s3c2410_gpio_setpin(S3C2410_GPB(1),0);
	s3c2410_gpio_cfgpin(S3C2410_GPH(10),S3C2410_GPIO_OUTPUT );
	s3c2410_gpio_setpin(S3C2410_GPH(10),0);
}
 
/*控制函数*/
static long motor_ioctl(
		struct file *file,
		unsigned int cmd,
		unsigned long arg)
{
    unsigned int direction;
	switch(cmd){
		case Age_Life:
            direction=1;
			Motor_Ferg(arg,direction);
			break;
 
        case Back_Life:
            direction=0;
            Motor_Ferg(arg,direction);
            break;
 
		case Car_Stop:
			Motor_Stop();
			break;
	}
	return 0;
}
 
/*打开函数*/
static int motor_open(struct inode *inode,struct file *file)
{
	if(!down_trylock(&lock))
		return	0;
	else
		return -EBUSY;
}
 
/*关闭函数*/
static int motor_release(struct inode *inode,struct file *file)
{
	Motor_Stop();
	up(&lock);
	return	0;
}
 
/*设置各函数*/
static struct file_operations motor_fops=
{
	.owner		= THIS_MODULE,
	.unlocked_ioctl = motor_ioctl,
	.release	= motor_release,
	.open		= motor_open,
};
 
/*注册驱动函数*/
static int __init motor_init(void)
{
	int ret,err;
	int major,minor;
	major=200;
	minor=0;
 
	sema_init(&lock,1);
	ret=register_chrdev_region(major,2,DEVICE_NAME);
 
	if(ret<0)
		return ret;
 
	devno=MKDEV(major,minor);
 
	motor_cdev=cdev_alloc();
	cdev_init(motor_cdev,&motor_fops);
	err=cdev_add(motor_cdev,devno,2);
	if(err)
	{
		unregister_chrdev_region(devno,2);
		return -EFAULT;
	}
 
	printk(DEVICE_NAME "\tinitialized!\n");
	return ret;
}
 
/*注销驱动函数*/
static void __exit motor_exit(void)
{
	cdev_del(motor_cdev);
	unregister_chrdev_region(devno,2);
	printk(DEVICE_NAME "\tunloaded\n");
}
 
module_init(motor_init);
module_exit(motor_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yayi");

Linux Office

Linux下有许许多多的OFFICE可以提供选择,
每一个都是具有自己不错的优点。
比较出名,具有人气的有:”openoffice、libreoffice、Koffice、永中Office …”。
这些都是比较重量级的Office,都是非常的不错的。
而这次主要介绍两个轻量级办公软件。
AbiWord
功能:类似windows office的Word。
官网:http://abisource.com/

 

 

Gnumeric
功能:类似windows office的excel。
官网:http://projects.gnome.org/gnumeric/

 

这两个配合起来,基本就是一个轻量级的Office了,基本都已经满足了办公需求。
但是公司的人多数还是使用着windows office,所以兼容问题还是值得深深的考虑。
不要辛苦在自己电脑完成的工作拷贝到公司后却出现了乱子。

Linux设备驱动(四)-中断服务

Linux中断服务大多数情况下,一个驱动程序只需要为它的设备注册一个中断处理例程,当有中断时进行正确的处理。内核负责维护了一个中断服务信号线的注册表,驱动程序在启动中断服务前会请求一个中断通道,使用完后会释放。

注册中断服务函数:
中断注册是使用了的”requset_irq“函数:

1
2
3
4
5
6
7
8
9
extern int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
            const char *name, void *dev);
 
irq:申请的硬件中断号
handler:向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它
*name:中断名称,/proc/interrupts中可以看到此名称
*dev:在中断共享时会用到,让handler知道是处理哪个中断,也可以用来指定中断服务函数需要参考的数据地址,一般设置为这个设备的设备结构体或者NULL
flags:中断处理的属性,详细参数在中说明.详细看代码1

代码1:

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
/*
 * These flags used only by the kernel as part of the
 * irq handling routines.
 *
 * IRQF_DISABLED - keep irqs disabled when calling the action handler.
 *                 DEPRECATED. This flag is a NOOP and scheduled to be removed
 * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator
 * IRQF_SHARED - allow sharing the irq among several devices
 * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
 * IRQF_TIMER - Flag to mark this interrupt as timer interrupt
 * IRQF_PERCPU - Interrupt is per cpu
 * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
 * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
 *                registered first in an shared interrupt is considered for
 *                performance reasons)
 * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
 *                Used by threaded interrupts which need to keep the
 *                irq line disabled until the threaded handler has been run.
 * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
 * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
 * IRQF_NO_THREAD - Interrupt cannot be threaded
 */
#define IRQF_DISABLED				0x00000020
#define IRQF_SAMPLE_RANDOM			0x00000040
#define IRQF_SHARED				0x00000080
#define IRQF_PROBE_SHARED			0x00000100
#define __IRQF_TIMER				0x00000200
#define IRQF_PERCPU					0x00000400
#define IRQF_NOBALANCING			0x00000800
#define IRQF_IRQPOLL				0x00001000
#define IRQF_ONESHOT				0x00002000
#define IRQF_NO_SUSPEND			0x00004000
#define IRQF_FORCE_RESUME			0x00008000
#define IRQF_NO_THREAD				0x00010000
 
#define IRQF_TIMER              (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)

关闭中断服务函数:

1
2
extern void disable_irq(unsigned int irq);
irq:需要屏蔽的硬件中断号

使能中断服务函数:

1
2
extern void enable_irq(unsigned int irq);
irq:需要使能硬件中断号

释放中断服务函数:

1
2
3
void free_irq (unsigned int irq, void *dev_id);
irq:将要注销掉的中断服务函数的中断号;
dev_id:值指定与"request_irq()"函数中使用的"dev_id"值相同的值

中断处理例程的返回值说明:
中断处理例程应当返回一个值指示是否真正处理了一个中断。如果处理例程发现设备确实需要处理,应当返回”IRQ_HANDLED”; 否则返回值”IRQ_NONE”。
下面是文件的内容,更为详细的说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef _LINUX_IRQRETURN_H
#define _LINUX_IRQRETURN_H
 
/**
 * enum irqreturn
 * @IRQ_NONE            interrupt was not from this device
 * @IRQ_HANDLED         interrupt was handled by this device
 * @IRQ_WAKE_THREAD     handler requests to wake the handler thread
 */
enum irqreturn {
        IRQ_NONE                = (0 << 0),
        IRQ_HANDLED             = (1 << 0),
        IRQ_WAKE_THREAD         = (1 << 1),
};
 
typedef enum irqreturn irqreturn_t;
#define IRQ_RETVAL(x)   ((x) != IRQ_NONE)
 
#endif

当硬件中断到达处理器时, 内核提供的一个内部计数器会递增,产生的中断报告显示在”/proc/interrupts”中。这一方法可以用来检查设备是否按预期地工作。此文件只显示当前已安装处理例程的中断的计数。若以前request_irq的一个中断,现在已经free_irq了,那么就不会显示在这个文件中,但是它可以显示终端共享的情况。

“/proc/stat”记录了几个关于系统活动的底层统计信息, 包括(但不仅限于)自系统启动以来收到的中断数。 stat 的每一行以一个字符串开始, 是该行的关键词:intr 标志是中断计数。第一个数是所有中断的总数, 而其他每一个代表一个单独的中断线的计数, 从中断 0 开始(包括当前没有安装处理例程的中断),无法显示终端共享的情况。

以上两个文件的一个不同是:”/proc/interrupts”几乎不依赖体系,而”/proc/stat”的字段数依赖内核下的硬件中断,其定义在中。

Linux设备驱动(三)-file_operations结构体

字符设备驱动一旦注册完后就会进入file_operations结构体对设备操作进行定义。
file_operations:是一个字符设备把驱动的操作和设备号联系在一起的纽带,是一系列指针的集合,把系统调用与驱动程序关联起来的关键数据结构,这个结构体的每个成员都对应着一个系统调用。
传统上, 一个 file_operations结构或者其一个指针称为 fops( 或者它的一些变体). 结构中的每个成员必须指向驱动中的函数, 这些函数实现一个特别的操作, 或者对于不支持的操作留置为 NULL. 当指定为 NULL 指针时内核的确切的行为是每个函数不同的。
file_operations中不少参数包含字串”__user”,这种注解是一种文档形式, 注意, 一个指针是一个不能被直接解引用的用户空间地址. 对于正常的编译”__user”没有效果, 但是它可被外部检查软件使用来找出对用户空间地址的错误使用。
下面看看file_operations中的注释:

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
struct file_operations {
	struct module *owner;
	//所属模块,新注册的设备必须由"THIS_MODULE"这个值来指定
	loff_t (*llseek) (struct file *, loff_t, int);
	//定位文件当前的读写位置
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	//从设备中同步读取数据
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	//向设备同步发送(写入)数据
	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	//初始化一个异步的读取操作
	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
	//初始化一个异步的发送(写入)操作
	int (*readdir) (struct file *, void *, filldir_t);
	//仅用于读取目录,对于设备文件,该字段为NULL
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	//轮询函数,判断目前是否可以进行非阻塞的读取或者写入操作
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	//不使用BLK文件系统,将使用此钟函数指针代替ioctl
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	//在64位系统上,32位的ioctl调用将使用此函数指针代替
	int (*mmap) (struct file *, struct vm_area_struct *);
	//用于请教设备内存映射到进程地址空间
	int (*open) (struct inode *, struct file *);
	//打开函数
	int (*flush) (struct file *, fl_owner_t id);
	//发生在进程关闭设备文件描述符副本,执行并等待,若设置为NULL,内核将忽略用户应用程序的请求
	int (*release) (struct inode *, struct file *);
	//关闭函数
	int (*fsync) (struct file *, int datasync);
	//刷新等待处理的数据
	int (*aio_fsync) (struct kiocb *, int datasync);
	//异步的fsync
	int (*fasync) (int, struct file *, int);
	//通知设备FASYNC标志发生变化
	int (*lock) (struct file *, int, struct file_lock *);
	// 实现文件锁,设备驱动常不去实现此lock
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	//内核调用将其数据发送到对应文件,每次一个数据页,设备驱动通常将其设置为NULL
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	//允许模块检查船体给fcntl(F_SETEL...)调用的标志
	int (*flock) (struct file *, int, struct file_lock *);
	//实现文件锁
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	//readv和weritev:分散/聚集型的读写操作
	int (*setlease)(struct file *, long, struct file_lock **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
			  loff_t len);
};

一般比较常用的有read,write,open,llseek,unlocked_ioctl,poll和mmap。

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
int (*open)(struct inode *inode, struct file *filp);
功能:打开文件指针为filp,文件节点为inode的文件
 
int (*release) (struct inode *inode, struct file *filp);
功能:关闭文件指针为filp,文件节点为inode的文件
 
ssize_t (*read) (struct file *filp, char __user *buff, size_t count, loff_t *offp);
功能:把文件指针filp所指定文件的当前位置offp中读取count大小的数据到buff所指向的缓冲区
 
ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp);
功能:把buff所指向的缓冲区中count大小的数据写入到文件指针filp所指定文件的当前位置offp中
 
unsigned int (*poll) (struct file *filp, struct poll_table_struct *wait);
功能:如果进程发生阻塞则则使用poll_wait()函数把指定的等待队列添加到wait中,并返回描述设备的掩码
掩码取值:
POLLIN		设备可读
POLLRDNORM	数据可读
POLLOUT	设备可写
POLLWRNORM	数据可写
 
loff_t (*llseek) (struct file *filp, loff_t p, int where);
功能:定位文件指针filp的起始地址where中目标偏移P的位置
where取值:
SEEK_SET	0	文件开头
SEEK_CUR	1	当前位置
SEEK_END	2	文件末尾

然活我们通过一个驱动列子来对比这些成员的使用。

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/gpio.h>
 
#define DEVICE_NAME "buttons"
 
static struct cdev *buttons_cdev;
 
static dev_t devno;
 
static volatile char keystatus[]= {'0', '0', '0', '0', '0', '0'};
 
static volatile int press = 0;
 
static DECLARE_WAIT_QUEUE_HEAD(buttons_wait);
 
struct buttons_irq_desc
{
	int irq;
	int pin;
	int pin_set;
	int number;
	char *name;
};
 
static struct buttons_irq_desc buttons_irq[]=
{
	{IRQ_EINT8 ,S3C2410_GPG(0),S3C2410_GPG0_EINT8 ,0,"KEY0"},
	{IRQ_EINT11,S3C2410_GPG(3),S3C2410_GPG3_EINT11,1,"KEY1"},
	{IRQ_EINT13,S3C2410_GPG(5),S3C2410_GPG5_EINT13,2,"KEY2"},
	{IRQ_EINT14,S3C2410_GPG(6),S3C2410_GPG6_EINT14,3,"KEY3"},
	{IRQ_EINT15,S3C2410_GPG(7),S3C2410_GPG7_EINT15,4,"KEY4"},
	{IRQ_EINT19,S3C2410_GPG(11),S3C2410_GPG11_EINT19,5,"KEY5"},
};
 
static irqreturn_t buttons_interrupt(int irq,void *dev_id)
{
	struct buttons_irq_desc *buttons_irq = (struct buttons_irq_desc *)dev_id;
	int down;
	down=!s3c2410_gpio_getpin(buttons_irq->pin);
	if(down!=(keystatus[buttons_irq->number] & 1))
	{
		keystatus[buttons_irq->number]='0'+down;
		press=1;
		wake_up_interruptible(&buttons_wait);
	}
	return IRQ_RETVAL(IRQ_HANDLED);
}
 
static int buttons_open(struct inode *inode,struct file *filp)
{
	int i;
	int err=0;
	for (i = 0; i < 6; i++)
	{
		if(buttons_irq[i].irq<0)
		{
			continue;
		}
		err=request_irq(buttons_irq[i].irq,buttons_interrupt,IRQ_TYPE_EDGE_BOTH,buttons_irq[i].name,(void *)&buttons_irq[i]);
		if(err)
			break;
	}
	if(err)
	{
		i--;
		for(; i>=0; i--)
		{
			if (buttons_irq[i].irq < 0)
			{
				continue;
			}
			disable_irq(buttons_irq[i].irq);
			free_irq(buttons_irq[i].irq,(void *)&buttons_irq[i]);
		}
		return -EBUSY;
	}
	press = 1;
	return 0;
}
 
static int buttons_read(struct file *filp,char __user *buff,size_t count, loff_t *offp)
{
	unsigned long err;
	if (!press)
	{
		if (filp->f_flags & O_NONBLOCK)
			return -EAGAIN;
		else
			wait_event_interruptible(buttons_wait, press);
	}
	press = 0;
	err = copy_to_user(buff, (const void *)keystatus, min(sizeof(keystatus), count));
	return err ? -EFAULT : min(sizeof(keystatus), count);
}
 
static unsigned int buttons_poll( struct file *filp, struct poll_table_struct *wait)
{
	unsigned int mask = 0;
	poll_wait(filp, &buttons_wait, wait);
	if (press)
		mask |= POLLIN | POLLRDNORM;
	return mask;
}
 
static int buttons_close(struct inode *inode, struct file *filp)
{
	int i;
	for (i = 0; i < 6; i++)
	{
		if (buttons_irq[i].irq < 0)
		{
			continue;
		}
		free_irq(buttons_irq[i].irq, (void *)&buttons_irq[i]);
	}
	return 0;
}
 
static struct file_operations buttons_fops=
{
	.owner   = THIS_MODULE,
	.read	= buttons_read,
	.open	= buttons_open,
	.release = buttons_close,
	.poll	=   buttons_poll,
};
 
static int __init buttons_init(void)
{
	int ret,err;
	int major_no,monir_no;
	ret=alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
	if(ret)
		return ret;
	buttons_cdev=cdev_alloc();
	cdev_init(buttons_cdev,&buttons_fops);
	err=cdev_add(buttons_cdev,devno,1);
	if(err)
	{
		unregister_chrdev_region(devno,1);
		return -EFAULT;
	}
	major_no=MAJOR(devno);
	monir_no=MINOR(devno);
	printk(KERN_NOTICE "Major is: %d , Monir is: %d.\n", major_no, monir_no);
	printk(DEVICE_NAME "\tinitialized!\n");
	return 0;
}
 
static void __exit buttons_exit(void)
{
	cdev_del(buttons_cdev);
	unregister_chrdev_region(devno,1);
	printk(DEVICE_NAME "\tunloaded!\n");
}
 
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yayi");