⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtc.c

📁 freescale的关于Imax21的rtc程序,好用
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************	Copyright (C) 2002 Motorola GSG-China	This program is free software; you can redistribute it and/or	modify it under the terms of the GNU General Public License	as published by the Free Software Foundation; either version 2	of the License, or (at your option) any later version.	This program is distributed in the hope that it will be useful,	but WITHOUT ANY WARRANTY; without even the implied warranty of	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the	GNU General Public License for more details.	You should have received a copy of the GNU General Public License	along with this program; if not, write to the Free Software	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.*******************************************************************************/#define RTC_VERSION	"0.3.0"#define HW_2HZ#define RTC_IO_EXTENT	0x10	/* Only really two ports, but...	*/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/miscdevice.h>#include <linux/ioport.h>#include <linux/fcntl.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/proc_fs.h>#include <linux/spinlock.h>#include <linux/rtc.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#define DAYR			0xf0204020#define HOURMIN			0xf0204000#define SECONDS			0xf0204004#define DAYALARM		0xf0204024#define ALRM_HM			0xf0204008#define ALRM_SEC		0xf020400c#define RCCTL			0xf0204010#define RTCISR			0xf0204014#define RTCIENR			0xf0204018#define STPWCH			0xf020401c#define RTC_AIE			0x0004#define RTC_PIE			0xff80#define RTC_UIE			0x0010#define RTC_SIE			0x0001#define RTC_IRQ			17#ifdef _DEBUG_RTC#	define RTC_DB(fmt, args...) 	printk("\n[%s]:[line%d]----"fmt, __FILE__, __LINE__, ## args)#	define RTC_LOC			printk(KERN_ERR"\nCurrent Location [%s]:[%d]\n", __FILE__, __LINE__)#	define FUNC_START		printk(KERN_ERR"\n[%s]:start!\n", __FUNCTION__)#	define FUNC_END			printk(KERN_ERR"\n[%s]:end!\n", __FUNCTION__)#	define CLUE(arg)		printk(" %s\n",arg)#else#	define RTC_DB(fmt, args...)#	define RTC_LOC#	define FUNC_START#	define FUNC_END#endif#define TRY_SLEEPON//#define _DEBUG_RTCstruct rtc_time rtc_timer;static struct fasync_struct *rtc_async_queue;#ifdef TRY_SLEEPONwait_queue_head_t rtc_wait;#elsestatic DECLARE_WAIT_QUEUE_HEAD(rtc_wait);#endifextern spinlock_t rtc_lock;static struct timer_list rtc_irq_timer;static loff_t rtc_llseek(struct file *file, loff_t offset, int origin);static ssize_t rtc_read(struct file *file, char *buf,			size_t count, loff_t *ppos);static int rtc_ioctl(struct inode *inode, struct file *file,		     unsigned int cmd, unsigned long arg);#if RTC_IRQstatic unsigned int rtc_poll(struct file *file, poll_table *wait);#endifstatic void get_rtc_time (struct rtc_time *rtc_tm);static void get_rtc_alm_time (struct rtc_time *alm_tm);#if RTC_IRQstatic void rtc_dropped_irq(unsigned long data);static void set_rtc_irq_bit(unsigned int bit);static void mask_rtc_irq_bit(unsigned int bit);#endifstatic int rtc_read_proc(char *page, char **start, off_t off,                         int count, int *eof, void *data);unsigned int READREG(unsigned int r){	return *(volatile unsigned int *)r;}void WRITEREG(unsigned int r, unsigned int val){	*(volatile unsigned int *)r = val;}/* *	Bits in rtc_status. (6 bits of room for future expansion) */#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/#define RTC_TIMER_ON		0x02	/* missed irq timer active	*//* * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is * protected by the big kernel lock. However, ioctl can still disable the timer * in rtc_status and then with del_timer after the interrupt has read * rtc_status but before mod_timer is called, which would then reenable the * timer (but you would need to have an awful timing before you'd trip on it) */static unsigned long rtc_status = 0;	/* bitmapped status byte.	*/static unsigned long rtc_freq = 0;	/* Current periodic IRQ rate	*/static unsigned long rtc_irq_data = 0;	/* our output to the world	*/static unsigned long before_wk = 0;     /* the seconds value before set the stopwatch *//* *	If this driver ever becomes modularised, it will be really nice *	to make the epoch retain its value across module reload... */static unsigned long epoch = 1900;	/* year corresponding to 0x00	*/static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};#if RTC_IRQ/* *	A very tiny interrupt handler. It runs with SA_INTERRUPT set, *	but there is possibility of conflicting with the set_rtc_mmss() *	call (the rtc irq and the timer irq can easily run at the same *	time in two different CPUs). So we need to serializes *	accesses to the chip with the rtc_lock spinlock that each *	architecture should implement in the timer code. *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) */static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs){	/*	 *	Can be an alarm interrupt, update complete interrupt,	 *	or a periodic interrupt. We store the status in the	 *	low byte and the number of interrupts received since	 *	the last read in the remainder of rtc_irq_data.	 */	static int freq_2HZ = 0;	unsigned long isr;#ifndef HW_2HZ	if ((rtc_freq == 2 ) && (freq_2HZ == 0))	{			freq_2HZ = 1;		/* clear RTCISR */		WRITEREG(RTCISR, READREG(RTCISR)); 				return;	}#endif	freq_2HZ = 0;	spin_lock (&rtc_lock);	rtc_irq_data += 0x10000; /* 0x100 */	rtc_irq_data &= ~0xffff;	rtc_irq_data |= (READREG(RTCISR) & 0xffff);	RTC_DB(" rtc_irq_data 0x%lx",rtc_irq_data);	//acknowledge the interrupt 		isr =READREG(RTCISR);	RTC_DB("before setting RTCISR is 0x%lx",isr);	WRITEREG(RTCISR, READREG(RTCISR)); 	isr =READREG(RTCISR);	RTC_DB("aftre setting RTCISR is 0x%lx",isr);	if (rtc_status & RTC_TIMER_ON)		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);	spin_unlock (&rtc_lock);	/* Now do the rest of the actions */	wake_up_interruptible(&rtc_wait);		kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);	}#endif/* *	Now all the various file operations that we export. */static loff_t rtc_llseek(struct file *file, loff_t offset, int origin){	return -ESPIPE;}#ifdef  ZHIMING_VERSIONstatic ssize_t rtc_read(struct file *file, char *buf,			size_t count, loff_t *ppos){	//	FUNC_START; //??? why error here?#if !RTC_IRQ	return -EIO;#else	DECLARE_WAITQUEUE(wait, current);	unsigned long data,j;	ssize_t retval;		if (count < sizeof(unsigned long))		return -EINVAL;#if 0	add_wait_queue(&rtc_wait, &wait);	current->state = TASK_INTERRUPTIBLE;#endif			do {		/* First make it right. The make it fast. Putting this whole		 * block within the parentheses of a while would be too		 * confusing. And no, xchg() is not the answer. */		spin_lock_irq (&rtc_lock);		data = rtc_irq_data;		rtc_irq_data = 0;		spin_unlock_irq (&rtc_lock);		if (data != 0)			break;		if (file->f_flags & O_NONBLOCK) {			retval = -EAGAIN;			goto out;		}#if 0		if (signal_pending(current)) {			retval = -ERESTARTSYS;			goto out;		}		schedule();#endif	} while (1);	/* wait some seconds to get the accurate watchstop */#if 1	j = jiffies+before_wk*HZ;	RTC_DB("befor_wk = 0x%lx",before_wk);	before_wk = 0;	while(jiffies < j)		schedule();#endif#if 0	current ->timeout = j;	current->state = TASK_INTERRUPTIBLE;	schedule();	current ->timeout = 0;#endif	retval = put_user(data, (unsigned long *)buf); 	if (!retval)		retval = sizeof(unsigned long);  out:#if 0	current->state = TASK_RUNNING;	remove_wait_queue(&rtc_wait, &wait);#endif		return retval;#endif}#else //!ZHIMING_VERSIONstatic ssize_t rtc_read(struct file *file, char *buf,			size_t count, loff_t *ppos){	//	FUNC_START; //??? why error here?#if !RTC_IRQ	return -EIO;#else#ifdef TRY_SLEEPON	unsigned long data;	unsigned int j;	ssize_t retval;	if(count < sizeof(unsigned long))		return -EINVAL;	/* First make it right. The make it fast. Putting this whole	 * block within the parentheses of a while would be too	 * confusing. And no, xchg() is not the answer. */	spin_lock_irq (&rtc_lock);	data = rtc_irq_data;	rtc_irq_data = 0;	spin_unlock_irq (&rtc_lock);	if(file->f_flags & O_NONBLOCK){		if(!data)			return -EAGAIN;		retval = put_user(data, (unsigned long *)buf); 		return retval; 	}else{		while(1){ //ensure copy to user or block			spin_lock_irq (&rtc_lock);			data = rtc_irq_data;			rtc_irq_data = 0;			spin_unlock_irq (&rtc_lock);			if(data){#if 1	j = jiffies+before_wk*HZ;	RTC_DB("befor_wk = 0x%lx",before_wk);	before_wk = 0;	while(jiffies < j)		schedule();#endif				return put_user(data, (unsigned long *)buf);			}else{				interruptible_sleep_on(&rtc_wait);				// TODO				if(signal_pending(current))					return -ERESTARTSYS;			}		}	}	#else //!TRY_SLEEPON	DECLARE_WAITQUEUE(wait, current);	unsigned long data;	ssize_t retval;		if (count < sizeof(unsigned long))		return -EINVAL;	add_wait_queue(&rtc_wait, &wait);	current->state = TASK_INTERRUPTIBLE;		do {		/* First make it right. The make it fast. Putting this whole		 * block within the parentheses of a while would be too		 * confusing. And no, xchg() is not the answer. */		spin_lock_irq (&rtc_lock);		data = rtc_irq_data;		rtc_irq_data = 0;		spin_unlock_irq (&rtc_lock);		if (data != 0)			break;		if (file->f_flags & O_NONBLOCK) {			retval = -EAGAIN;			goto out;		}		if (signal_pending(current)) {			retval = -ERESTARTSYS;			goto out;		}		schedule();	} while (1);		retval = put_user(data, (unsigned long *)buf); 	if (!retval)		retval = sizeof(unsigned long); out: 	current->state = TASK_RUNNING;	remove_wait_queue(&rtc_wait, &wait);		return retval;#endif // TRY_SLEEPON#endif // !RTC_IRQ}#endif // ZhimingVersionstatic int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,		     unsigned long arg){	struct rtc_time wtime;//	unsigned int j;		;	switch (cmd) {#if RTC_IRQ	case RTC_WIE_OFF:	/* mask stop watch int. enab. bit */	{		mask_rtc_irq_bit(RTC_SIE);		return 0;	}	case RTC_WIE_ON:	{		set_rtc_irq_bit(RTC_SIE);		return 0;	}	case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/	{		mask_rtc_irq_bit(RTC_AIE);		return 0;	}	case RTC_AIE_ON:	/* Allow alarm interrupts.	*/	{		set_rtc_irq_bit(RTC_AIE);		return 0;	}	case RTC_PIE_OFF:	/* Mask periodic int. enab. bit	*/	{		mask_rtc_irq_bit(rtc_freq ==1 ? rtc_freq <<4 : rtc_freq << 6);		if (rtc_status & RTC_TIMER_ON) {			spin_lock_irq (&rtc_lock);			rtc_status &= ~RTC_TIMER_ON;			del_timer(&rtc_irq_timer);			spin_unlock_irq (&rtc_lock);		}		return 0;	}	case RTC_PIE_ON:	/* Allow periodic int in RTCISR [bit 7~bit 15]*/	{		/*		 * We don't really want Joe User enabling more		 * than 64Hz of interrupts on a multi-user machine.		 * you can see linux\include\linux\capablities.h 		 */		if ((rtc_freq > 64) && (!capable(CAP_SYS_RESOURCE)))			return -EACCES;				if (!(rtc_status & RTC_TIMER_ON)) {			spin_lock_irq (&rtc_lock);			rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;			add_timer(&rtc_irq_timer);			rtc_status |= RTC_TIMER_ON;			spin_unlock_irq (&rtc_lock);		}			/* rtc_freq = 1HZ RTCISR[bit :4]		 * rtc_freq = 2HZ RTCISR[bit :7]		 * rtc_freq = 4HZ RTCISR[bit :8]		 * ...		 * rtc_freq = 512HZ RTCISR[bit :15]		 */		//set_rtc_irq_bit(rtc_freq << 6);				set_rtc_irq_bit((rtc_freq ==1) ? (rtc_freq<<4): (rtc_freq<<6));		return 0;	}	case RTC_UIE_OFF:	/* Mask ints from RTC updates.	*/	{		mask_rtc_irq_bit(RTC_UIE);//???		return 0;	}	case RTC_UIE_ON:	/* Allow ints for RTC updates.	*/	{		set_rtc_irq_bit(RTC_UIE);		return 0;	}#endif	case RTC_WKALM_SET:	{		if (arg > 0x3f)			return -EFAULT;		spin_lock_irq(&rtc_lock);		before_wk = READREG(SECONDS) & 0x3f;		WRITEREG(STPWCH, arg);		spin_unlock_irq(&rtc_lock);		return 0;	}	case RTC_WKALM_RD:	{		unsigned int val;		val = READREG(STPWCH);		return put_user(val, (unsigned long *)arg);	}	case RTC_ALM_READ:	/* Read the present alarm time */	{		/*		 * This returns a struct rtc_time. Reading >= 0xc0		 * means "don't care" or "match all". Only the tm_hour,		 * tm_min, and tm_sec values are filled in.		 */		get_rtc_alm_time(&wtime);		break; 	}	case RTC_ALM_SET:	/* Store a time into the alarm */	{		/*		 * This expects a struct rtc_time. Writing 0xff means		 * "don't care" or "match all". Only the tm_hour,		 * tm_min and tm_sec are used.		 */		unsigned char day, hrs, min, sec;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -