2440按键恢复初始配置

目的是实现,通过板子上一按钮来控制系统恢复初始配置。 其实也就是在应用层将备份文件 覆盖 配置文件这一个操作而已。

按键恢复默认配置,其基本的思想是 中断+ 应用阻塞。

前前后后花了挺多的时间,看了中断的理论,看了寄存器的配置,还去看输入子系统,有些步骤是不必要的,但是做的时候并不知道不需要。

最后的实验,代码的大部分都是借用人家的。自己仅看的懂代码而已,如果自己去写一份,估计写不出来。

连接如下:http://wenku.baidu.com/view/c82df93283c4bb4cf7ecd181.html

自己在看对方代码的时候,有许多地方不太明白,因此把查阅的一些信息也都写进代码的注释中了。

另外poll 是一种监听机制,对自己方案的实现没有任何作用(参阅部分资料后得出的结论)。所以就没有注册这个方法。

关于寄存器的操作时看 datasheet里的,不过操作系统做了这部分的工作,自己画蛇添足了。 而关于清中断这一步,都说是要手动进行的,查了半天的资料都没有看到相关的配置,于是也就放弃了。

#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/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <mach/regs-irq.h>


#define DEVICE_NAME "RESTORE_BUTTON"
//#define S3C2410_GPF2 162

struct button_irq_desc
{
	int irq;
	int pin;
	int pin_setting;
	char * name;
};

// 这一部分还得看看具体情形才好。2不是被占用了么?被加密芯片
//IRQ_EINT2 = 16+2 =18
//S3C2410_GPF2 = 32x5+2 =162
//S3C2410_GPF2_EINT2 = 0x02 << 4
//触发设置为上升沿触发,因此
static struct button_irq_desc button=
{
	IRQ_EINT2,S3C2410_GPF2,S3C2410_GPF2_EINT2,"RESTORE_BUTTON"
};

//设置等待队列
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
//按键进行记录
static volatile int ev_press = 0;

//触发设置为下降沿触发
//中断处理函数,由中断号和中断结构体组成。
static irqreturn_t irq_interrupt(int irq,void *dev_id)
{
	printk("%s",dev_id);  // 原先中断有问题的,就是kernel panic,加了这句竟然莫名好了,摸不着头脑。 没有再试验了
	struct button_irq_desc * button_irq = (struct button_irq_desc*) dev_id;
	int down;

	// 这一部分的工作 为清理中断的工作,是否也被操作系统做完了?
	//unsigned long srcpnd;
	// 进入中断处理函数,现在可以清中断了。
	//srcpnd = __raw_readl(S3C2410_SRCPND);
	// 取反之后 再与操作
	//srcpnd &=(~(1<<2));
	//__raw_writel(srcpnd,S3C2410_SRCPND);
	// 取值,值并不一定为1,可能为其他数值,但是不影响为真。

	down=s3c2410_gpio_getpin(button_irq->pin);
	if(!down)
	{
		// 记录按键被按下
		ev_press=1;//;
		//唤醒指定的注册在等待队列button_waitq 上的进程。该函数不能直接的立即唤醒进程,
		//而是由调度程序转换上下文,调整为可运行状态。
		wake_up_interruptible(&button_waitq);
	}
	// 表示中断处理结束
	return IRQ_RETVAL(IRQ_HANDLED);
}

//register the interrupt,when failed ,quit;
static int irq_open(int irq,void *dev_id)
{
	int err=0;

	s3c2410_gpio_cfgpin(S3C2410_GPF2,S3C2410_GPF2_EINT2);
	err = request_irq(button.irq,irq_interrupt,IRQ_TYPE_EDGE_FALLING,button.name,(void*)&button);
	//对应中断号,中断处理函数,中断触发,中断名,设备结构体
	// 正常时返回0 ,负责返回对应错误的负值。
	if(err)
		return -EBUSY;

	return 0;
}

//释放已经注册的中断
static int irq_close(struct inode* inode,struct file *file)
{
	free_irq(button.irq,(void*)&button);
	
	return 0;
};

static volatile char key_values[]={'0','0','0'}


static int irq_read(struct file* file,char __user *buff,size_t count)//)
{
	//3unsigned long err;
	//ev_press为0,表明按钮未被按下
	if (!ev_press)
	{
		// nonblock 为非阻塞的意思
		// 即先判断文件描述符是否支持阻塞
		if (file->f_flags & O_NONBLOCK)
			return -EAGAIN;
		// 支持阻塞,则进入阻塞队列,等待被唤醒
		// 若ev_press 为1的话,则被唤醒
		else
		//将当前进程加入到等待队列button_waitq中,并在内部访问ev_press看值是否成立。
		// 将标志位设置为TASK_INTTUPTABLE 并从runqueue 中删除,同时调用onshedule
		// 当前进程则进入等待队列,不被执行,即睡眠了。
			wait_event_interruptible(button_waitq, ev_press);
	}
	// 将ev_press 重置为0
	ev_press = 0;
	//  将值传递到用户空间,数据已经被读取。
	// 需要改动
	err = copy_to_user(buff, (const void *)key_values,count));
	// 即完成读取这个过程即可,并不需要真正的数据传输
	// 这里返回的是什么?
	//return err ? -EFAULT : min(sizeof(key_values), count);
	// 直接返回0 ,表示程序运行完了。即可。
	return 0;
};

//监听函数,即监听当前进程,这里没有放入操作列表中。
//这里没有使用监听函数实现
static unsigned int irq_poll(struct file *file,struct poll_table_struct * wait)
{
	unsigned int mask = 0;
	// 将当前进程放入等待队列中
	// poll_wait()函数会监测进程队列button_waitq里的进程
	// 它的作用就是把当前进程添加到wait参数指定的等待列表(poll_table)中
	// 首先调用poll_wait将等待队列添加到wait结构中
	poll_wait(file,&button_waitq,wait);
	if(ev_press)
		mask |=POLLIN|POLLRDNORM; // 有数据可读
	return mask; // 返回事件记录,若是0表示等待事件超时。
};

static struct file_operations dev_fops =
{
	.owner = THIS_MODULE,
	.open = irq_open,
	.release = irq_close,
	.read = irq_read,
//	.poll = irq_poll;
};

static struct miscdevice misc=
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dev_fops,
};

static int __init dev_init(void)
{
	int ret;
	//unsigned long intmod;
	//unsigned long intmask;

	ret = misc_register(&misc);
	printk(DEVICE_NAME" initialized\n");
	if(ret<0){
		 printk("Add cdev failed!\n");
		}
	// 查到资料说寄存器的设置,操作系统已经做好了,自己这一部分的工作就有点画蛇添足了。
	// 对中断寄存器的设置,初始化部分
	// INTMOD 中断模式寄存器,设置为快中断,为1
	// INTMASK 中断屏蔽寄存器,设置为0,表示响应中断
	// 其中还要对寄存器SRCPEND进行中断清除,具体在代码那个位置还需要商榷
	// 要定位这些寄存器的位置在哪里,并且进行设置。
	//#define S3C2410_SRCPND	       S3C2410_IRQREG(0x000)
	//#define S3C2410_INTMOD	       S3C2410_IRQREG(0x004)
	//#define S3C2410_INTMSK	       S3C2410_IRQREG(0x008)
	// 寄存器设置使用方法。
	// 设置管脚为中断模式
	//设置中断模式和中断屏蔽
	//intmod = __raw_readl(S3C2410_INTMOD);
	//将INTMOD 相应位 设置为1,即为快中断,同时写回寄存器中。
	//具体哪一位,看 S3C2440 datasheet
	//intmod = intmod|(1<<2);
	//__raw_writel(intmod,S3C2410_INTMOD);
	//将中断服务设置为可服务
	//其他位置保持不变。
	//intmask = __raw_readl(S3C2410_INTMSK);
	//intmask = intmask&(~(1<<2));
	//__raw_writel(intmask,S3C2410_INTMSK);
	return ret;
}

static int __exit dev_exit(void)
{
	
	misc_deregister(&misc);
	return 0;
}

module_init(dev_init);
module_exit(dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("csw");
MODULE_DESCRIPTION("IRQ for restore IP");



/* 如果当前不可读,那么在sys_poll->do_poll中当前进程就会睡眠在等待队列上,
 * 这个等待队列是由驱动程序提供的(就是poll_wait中传入的那个)。当可读的时候,
 * 驱动程序可能有一部分代码运行了(比如驱动的中断服务程序),那么在这部分代码中,
 * 就会唤醒等待队列上的进程,也就是之前睡眠的那个,当那个进程被唤醒后do_poll会再一次的
 * 调用驱动程序的poll函数,这个时候应用程序就知道是可读的了。

 * POOL方法就是用来支持非阻塞式的访问,当然是立即返回,但是它会把这次请求放入一个等待 
 * 队列中,当某个条件满足时,内核会通知应用程序(应用程序的select函数会感知),然后就
 * 会接着select操作

 *poll_wait不会挂起当前进程,而是把自己注册到某个事件等待队列中.
 *poll_wait()是用在select系统调用中的. 
 */

应用程序部分就没贴了,因为忘记从linux 的 home 路径下拷贝过来了。

应用程序主要实现的就是去读取对应的设备文件,当读到字符的时候,就实现拷贝工作,读取不到的时候就阻塞睡眠了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章