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

📄 rtc.c

📁 freescale的关于Imax21的rtc程序,好用
💻 C
📖 第 1 页 / 共 2 页
字号:
		struct rtc_time alm_tm;		if (copy_from_user(&alm_tm, (struct rtc_time*)arg,				   sizeof(struct rtc_time)))			return -EFAULT;		day = alm_tm.tm_mday;		hrs = alm_tm.tm_hour;		min = alm_tm.tm_min;		sec = alm_tm.tm_sec;		if (hrs >= 24)			hrs = 0xff;		if (min >= 60)			min = 0xff;		if (sec >= 60)			sec = 0xff;		spin_lock_irq(&rtc_lock);		WRITEREG(DAYALARM, day);		WRITEREG(ALRM_HM, (hrs << 8 | min));		WRITEREG(ALRM_SEC, sec);		spin_unlock_irq(&rtc_lock);		return 0;	}	case RTC_RD_TIME:	/* Read the time/date from RTC	*/	{		get_rtc_time(&wtime);		break;	}	case RTC_SET_TIME:	/* Set the RTC */	{		struct rtc_time rtc_tm;		unsigned char mon, day, hrs, min, sec, leap_yr;		unsigned int yrs;		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,				   sizeof(struct rtc_time)))			return -EFAULT;		yrs = rtc_tm.tm_year + 1900;		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */		day = rtc_tm.tm_mday;		hrs = rtc_tm.tm_hour;		min = rtc_tm.tm_min;		sec = rtc_tm.tm_sec;		if (yrs < 1970)			return -EINVAL;		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));		if ((mon > 12) || (day == 0))			return -EINVAL;		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))			return -EINVAL;					if ((hrs >= 24) || (min >= 60) || (sec >= 60))			return -EINVAL;		if ((yrs -= epoch) > 255)    /* They are unsigned */			return -EINVAL;		spin_lock_irq(&rtc_lock);		WRITEREG(DAYR, day);		WRITEREG(HOURMIN, hrs << 8 | min);		WRITEREG(SECONDS, sec);		spin_unlock_irq(&rtc_lock);		rtc_timer.tm_year = yrs;		rtc_timer.tm_mon = mon;		return 0;	}#if RTC_IRQ	case RTC_IRQP_READ:	/* Read the periodic IRQ rate.	*/	{		return put_user(rtc_freq, (unsigned long *)arg);	}	case RTC_IRQP_SET:	/* Set periodic IRQ rate to rtc_freq */	{		int tmp = 0;		/* 		 * The range we can do is 1,2,4,8.. 512Hz.		 */		if (((arg < 2) || (arg > 512))&& arg != 1)			return -EINVAL;		while (arg > (1<<tmp))/* get the power of arg */ 			tmp++;		/*		 * Check that the input was really a power of 2.		 */		if (arg != (1<<tmp))			return -EINVAL;		spin_lock_irq(&rtc_lock);		rtc_freq = arg;		spin_unlock_irq(&rtc_lock);		return 0;	}#elif !defined(CONFIG_DECSTATION)	case RTC_EPOCH_READ:	/* Read the epoch.	*/	{		return put_user (epoch, (unsigned long *)arg);	}	case RTC_EPOCH_SET:	/* Set the epoch.	*/	{		/* 		 * There were no RTC clocks before 1900.		 */		if (arg < 1900)			return -EINVAL;		if (!capable(CAP_SYS_TIME))			return -EACCES;		epoch = arg;		return 0;	}#endif	default:		return -EINVAL;	}			return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;}/* *	We enforce only one user at a time here with the open/close. *	Also clear the previous interrupt data on an open, and clean *	up things on a close. *//* We use rtc_lock to protect against concurrent opens. So the BKL is not * needed here. Or anywhere else in this driver. */static int rtc_open(struct inode *inode, struct file *file){		spin_lock_irq (&rtc_lock);	if(rtc_status & RTC_IS_OPEN)		goto out_busy;	rtc_status |= RTC_IS_OPEN;	rtc_irq_data = 0;	spin_unlock_irq (&rtc_lock);		return 0;out_busy:	spin_unlock_irq (&rtc_lock);	return -EBUSY;}static int rtc_fasync (int fd, struct file *filp, int on){	return fasync_helper (fd, filp, on, &rtc_async_queue);}static int rtc_release(struct inode *inode, struct file *file){	#if RTC_IRQ	/*	 * Turn off all interrupts once the device is no longer	 * in use, and clear the data.	 */	spin_lock_irq(&rtc_lock);	if (rtc_status & RTC_TIMER_ON) {		rtc_status &= ~RTC_TIMER_ON;		del_timer(&rtc_irq_timer);	}	spin_unlock_irq(&rtc_lock);	if (file->f_flags & FASYNC) {		rtc_fasync (-1, file, 0);	}#endif	spin_lock_irq (&rtc_lock);	rtc_irq_data = 0;	spin_unlock_irq (&rtc_lock);	/* No need for locking -- nobody else can do anything until this rmw is	 * committed, and no timer is running. */	rtc_status &= ~RTC_IS_OPEN;		return 0;}#if RTC_IRQ/* Called without the kernel lock - fine */static unsigned int rtc_poll(struct file *file, poll_table *wait){	unsigned long l;	poll_wait(file, &rtc_wait, wait);	spin_lock_irq (&rtc_lock);	l = rtc_irq_data;	spin_unlock_irq (&rtc_lock);	if (l != 0)		return POLLIN | POLLRDNORM;	return 0;}#endif/* *	The various file operations we support. */static struct file_operations rtc_fops = {	owner:		THIS_MODULE,	llseek:		rtc_llseek,	read:		rtc_read,#if RTC_IRQ	poll:		rtc_poll,#endif	ioctl:		rtc_ioctl,	open:		rtc_open,	release:	rtc_release,	fasync:		rtc_fasync,};static struct miscdevice rtc_dev={	RTC_MINOR,	"rtc",	&rtc_fops};static int __init rtc_init(void){#ifdef KHz32768		WRITEREG(RCCTL, 0x01);	WRITEREG(RCCTL, 0x80);#else	WRITEREG(RCCTL, 0x01);	WRITEREG(RCCTL, 0xa0);#endif	rtc_timer.tm_mon = 0;	rtc_timer.tm_year = 0;#if RTC_IRQ	if(request_irq(RTC_IRQ, 				rtc_interrupt, 				SA_SHIRQ | SA_INTERRUPT, 				"rtc", 				"rtc"))	{		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);		return -EIO;	}		if(request_irq(RTC_IRQ + 1, 				rtc_interrupt, 				SA_SHIRQ |SA_INTERRUPT, 				"rtc smaple timer", 				"rtcst"))	{		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);		return -EIO;	}//Karen modify#endif	misc_register(&rtc_dev);	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);#if RTC_IRQ	init_timer(&rtc_irq_timer);	rtc_irq_timer.function = rtc_dropped_irq;	spin_lock_irq(&rtc_lock);	spin_unlock_irq(&rtc_lock);	rtc_freq = 512;#endif#ifdef TRY_SLEEPON	init_waitqueue_head(&rtc_wait);#endif 		printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");		return 0;}static void __exit rtc_exit (void){		remove_proc_entry ("driver/rtc", NULL);	misc_deregister(&rtc_dev);#if RTC_IRQ	free_irq (RTC_IRQ, "rtc");	free_irq (RTC_IRQ + 1, "rtcst");#endif}module_init(rtc_init);module_exit(rtc_exit);EXPORT_NO_SYMBOLS;#if RTC_IRQstatic void rtc_dropped_irq(unsigned long data){	unsigned long freq;			spin_lock_irq (&rtc_lock);	/* Just in case someone disabled the timer from behind our back... */	if (rtc_status & RTC_TIMER_ON)		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);	rtc_irq_data += ((rtc_freq/HZ)<<16);//((rtc_freq/HZ)<<8);	rtc_irq_data &= ~0xffff;		rtc_irq_data |= (READREG(RTCISR) & 0xffff);	freq = rtc_freq;	spin_unlock_irq(&rtc_lock);//	printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);	/* Now we have new data */	wake_up_interruptible(&rtc_wait);	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);	}#endif/* *	Info exported via "/proc/driver/rtc". */static int rtc_proc_output (char *buf){	char *p;	struct rtc_time tm;	unsigned long freq;	spin_lock_irq(&rtc_lock);	freq = rtc_freq;	spin_unlock_irq(&rtc_lock);	p = buf;	get_rtc_time(&tm);	/*	 * There is no way to tell if the luser has the RTC set for local	 * time or for Universal Standard Time (GMT). Probably local though.	 */	p += sprintf(p,		     "rtc_time\t: %02d:%02d:%02d\n"		     "rtc_date\t: %04d-%02d-%02d\n"	 	     "rtc_epoch\t: %04lu\n",		     tm.tm_hour, tm.tm_min, tm.tm_sec,		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);	get_rtc_alm_time(&tm);	/*	 * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will	 * match any value for that particular field. Values that are	 * greater than a valid time, but less than 0xc0 shouldn't appear.	 */	p += sprintf(p, "alarm\t\t: ");	if (tm.tm_hour <= 24)		p += sprintf(p, "%02d:", tm.tm_hour);	else		p += sprintf(p, "**:");	if (tm.tm_min <= 59)		p += sprintf(p, "%02d:", tm.tm_min);	else		p += sprintf(p, "**:");	if (tm.tm_sec <= 59)		p += sprintf(p, "%02d\n", tm.tm_sec);	else		p += sprintf(p, "**\n");	return  p - buf;}static int rtc_read_proc(char *page, char **start, off_t off,                         int count, int *eof, void *data){        int len = rtc_proc_output (page);        if (len <= off+count) *eof = 1;        *start = page + off;        len -= off;        if (len>count) len = count;        if (len<0) len = 0;        return len;}static void get_rtc_time(struct rtc_time *rtc_tm){	/*	 * Only the values that we read from the RTC are set. We leave	 * tm_wday, tm_yday and tm_isdst untouched. Even though the	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated	 * by the RTC when initially set to a non-zero value.	 */	spin_lock_irq(&rtc_lock);	rtc_tm->tm_sec = READREG(SECONDS);	rtc_tm->tm_min = READREG(HOURMIN) & 0x3f;	rtc_tm->tm_hour = (READREG(HOURMIN) >> 8 ) & 0x1f;	rtc_tm->tm_mday = READREG(DAYR);	rtc_tm->tm_mon = rtc_timer.tm_mon;	rtc_tm->tm_year = rtc_timer.tm_year;	spin_unlock_irq(&rtc_lock);	/*	 * Account for differences between how the RTC uses the values	 * and how they are defined in a struct rtc_time;	 */	if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)		rtc_tm->tm_year += 100;	rtc_tm->tm_mon--;	}static void get_rtc_alm_time(struct rtc_time *alm_tm){	/*	 * Only the values that we read from the RTC are set. That	 * means only tm_hour, tm_min, and tm_sec.	 */		spin_lock_irq(&rtc_lock);	alm_tm->tm_sec = READREG(ALRM_SEC);	alm_tm->tm_min = READREG(ALRM_HM) & 0x3f;	alm_tm->tm_hour = (READREG(ALRM_HM) >> 8) & 0x1f;	alm_tm->tm_mday = READREG(DAYALARM);	spin_unlock_irq(&rtc_lock);	}#if RTC_IRQ/* * Used to disable/enable interrupts for any one of UIE, AIE, PIE. * Rumour has it that if you frob the interrupt enable/disable * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to * ensure you actually start getting interrupts. Probably for * compatibility with older/broken chipset RTC implementations. * We also clear out any old irq data after an ioctl() that * meddles with the interrupt enable/disable bits. */static void mask_rtc_irq_bit(unsigned int bit){	spin_lock_irq(&rtc_lock);	/* for 2hz cant work well we use 4hz to simulate it */	if (bit == 0x80) //???		bit = 0x100;//	WRITEREG(RTCIENR, READREG(RTCIENR) & ~bit);		WRITEREG(RTCIENR, 0); //???	rtc_irq_data = 0;	spin_unlock_irq(&rtc_lock);}static void set_rtc_irq_bit(unsigned int bit){	spin_lock_irq(&rtc_lock);	/* use 4 hz to simulate 2hz */#ifndef HW_2HZ	if (bit == 0x80){		bit = 0x100;	}#endif	WRITEREG(RTCIENR, READREG(RTCIENR) | bit);		rtc_irq_data = 0;	spin_unlock_irq(&rtc_lock);}#endif

⌨️ 快捷键说明

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