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 路徑下拷貝過來了。

應用程序主要實現的就是去讀取對應的設備文件,當讀到字符的時候,就實現拷貝工作,讀取不到的時候就阻塞睡眠了。


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