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

📄 rtc.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		CMOS_WRITE(val, RTC_FREQ_SELECT);		restore_flags(flags);		return 0;	}#ifdef __alpha__	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. */static int rtc_open(struct inode *inode, struct file *file){	if(rtc_status & RTC_IS_OPEN)		return -EBUSY;	rtc_status |= RTC_IS_OPEN;	rtc_irq_data = 0;	return 0;}static int rtc_release(struct inode *inode, struct file *file){	/*	 * Turn off all interrupts once the device is no longer	 * in use, and clear the data.	 */	unsigned char tmp;	unsigned long flags;	save_flags(flags);	cli();	tmp = CMOS_READ(RTC_CONTROL);	tmp &=  ~RTC_PIE;	tmp &=  ~RTC_AIE;	tmp &=  ~RTC_UIE;	CMOS_WRITE(tmp, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	restore_flags(flags);	if (rtc_status & RTC_TIMER_ON) {		rtc_status &= ~RTC_TIMER_ON;		del_timer(&rtc_irq_timer);	}	rtc_irq_data = 0;	rtc_status &= ~RTC_IS_OPEN;	return 0;}static unsigned int rtc_poll(struct file *file, poll_table *wait){	poll_wait(file, &rtc_wait, wait);	if (rtc_irq_data != 0)		return POLLIN | POLLRDNORM;	return 0;}/* *	The various file operations we support. */static struct file_operations rtc_fops = {	rtc_llseek,	rtc_read,	NULL,		/* No write */	NULL,		/* No readdir */	rtc_poll,	rtc_ioctl,	NULL,		/* No mmap */	rtc_open,	NULL,		/* flush */	rtc_release};static struct miscdevice rtc_dev={	RTC_MINOR,	"rtc",	&rtc_fops};__initfunc(int rtc_init(void)){	unsigned long flags;#ifdef __alpha__	unsigned int year, ctrl;	unsigned long uip_watchdog;	char *guess = NULL;#endif	printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);	if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))	{		/* 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;	}	misc_register(&rtc_dev);	/* Check region? Naaah! Just snarf it up. */	request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");#ifdef __alpha__	rtc_freq = HZ;		/* Each operating system on an Alpha uses its own epoch.	   Let's try to guess which one we are using now. */		uip_watchdog = jiffies;	if (rtc_is_updating() != 0)		while (jiffies - uip_watchdog < 2*HZ/100)			barrier();		save_flags(flags);	cli();	year = CMOS_READ(RTC_YEAR);	ctrl = CMOS_READ(RTC_CONTROL);	restore_flags(flags);		if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)		BCD_TO_BIN(year);       /* This should never happen... */		if (year > 10 && year < 44) {		epoch = 1980;		guess = "ARC console";	} else if (year < 96) {		epoch = 1952;		guess = "Digital UNIX";	}	if (guess)		printk("rtc: %s epoch (%lu) detected\n", guess, epoch);#endif	init_timer(&rtc_irq_timer);	rtc_irq_timer.function = rtc_dropped_irq;	rtc_wait = NULL;	save_flags(flags);	cli();	/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);	restore_flags(flags);	rtc_freq = 1024;	return 0;}/* * 	At IRQ rates >= 4096Hz, an interrupt may get lost altogether. *	(usually during an IDE disk interrupt, with IRQ unmasking off) *	Since the interrupt handler doesn't get called, the IRQ status *	byte doesn't get read, and the RTC stops generating interrupts. *	A timer is set, and will call this function if/when that happens. *	To get it out of this stalled state, we just read the status. *	At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. *	(You *really* shouldn't be trying to use a non-realtime system  *	for something that requires a steady > 1KHz signal anyways.) */void rtc_dropped_irq(unsigned long data){	unsigned long flags;	printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq);	mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);	save_flags(flags);	cli();	rtc_irq_data += ((rtc_freq/HZ)<<8);	rtc_irq_data &= ~0xff;	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */	restore_flags(flags);}/* *	Info exported via "/proc/rtc". */int get_rtc_status(char *buf){	char *p;	struct rtc_time tm;	unsigned char batt, ctrl;	unsigned long flags;	save_flags(flags);	cli();	batt = CMOS_READ(RTC_VALID) & RTC_VRT;	ctrl = CMOS_READ(RTC_CONTROL);	restore_flags(flags);	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");	p += sprintf(p,		     "DST_enable\t: %s\n"		     "BCD\t\t: %s\n"		     "24hr\t\t: %s\n"		     "square_wave\t: %s\n"		     "alarm_IRQ\t: %s\n"		     "update_IRQ\t: %s\n"		     "periodic_IRQ\t: %s\n"		     "periodic_freq\t: %ld\n"		     "batt_status\t: %s\n",		     (ctrl & RTC_DST_EN) ? "yes" : "no",		     (ctrl & RTC_DM_BINARY) ? "no" : "yes",		     (ctrl & RTC_24H) ? "yes" : "no",		     (ctrl & RTC_SQWE) ? "yes" : "no",		     (ctrl & RTC_AIE) ? "yes" : "no",		     (ctrl & RTC_UIE) ? "yes" : "no",		     (ctrl & RTC_PIE) ? "yes" : "no",		     rtc_freq,		     batt ? "okay" : "dead");	return  p - buf;}/* * Returns true if a clock update is in progress */static inline unsigned char rtc_is_updating(void){	unsigned long flags;	unsigned char uip;	save_flags(flags);	cli();	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);	restore_flags(flags);	return uip;}void get_rtc_time(struct rtc_time *rtc_tm){	unsigned long flags, uip_watchdog = jiffies;	unsigned char ctrl;	/*	 * read RTC once any update in progress is done. The update	 * can take just over 2ms. We wait 10 to 20ms. There is no need to	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.	 * If you need to know *exactly* when a second has started, enable	 * periodic update complete interrupts, (via ioctl) and then 	 * immediately read /dev/rtc which will block until you get the IRQ.	 * Once the read clears, read the RTC time (again via ioctl). Easy.	 */	if (rtc_is_updating() != 0)		while (jiffies - uip_watchdog < 2*HZ/100)			barrier();	/*	 * 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.	 */	save_flags(flags);	cli();	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);	ctrl = CMOS_READ(RTC_CONTROL);	restore_flags(flags);	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)	{		BCD_TO_BIN(rtc_tm->tm_sec);		BCD_TO_BIN(rtc_tm->tm_min);		BCD_TO_BIN(rtc_tm->tm_hour);		BCD_TO_BIN(rtc_tm->tm_mday);		BCD_TO_BIN(rtc_tm->tm_mon);		BCD_TO_BIN(rtc_tm->tm_year);	}	/*	 * 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--;}void get_rtc_alm_time(struct rtc_time *alm_tm){	unsigned long flags;	unsigned char ctrl;	/*	 * Only the values that we read from the RTC are set. That	 * means only tm_hour, tm_min, and tm_sec.	 */	save_flags(flags);	cli();	alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);	alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM);	alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM);	ctrl = CMOS_READ(RTC_CONTROL);	restore_flags(flags);	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)	{		BCD_TO_BIN(alm_tm->tm_sec);		BCD_TO_BIN(alm_tm->tm_min);		BCD_TO_BIN(alm_tm->tm_hour);	}}/* * 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. */void mask_rtc_irq_bit(unsigned char bit){	unsigned char val;	unsigned long flags;	save_flags(flags);	cli();	val = CMOS_READ(RTC_CONTROL);	val &=  ~bit;	CMOS_WRITE(val, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	restore_flags(flags);	rtc_irq_data = 0;}void set_rtc_irq_bit(unsigned char bit){	unsigned char val;	unsigned long flags;	save_flags(flags);	cli();	val = CMOS_READ(RTC_CONTROL);	val |= bit;	CMOS_WRITE(val, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	rtc_irq_data = 0;	restore_flags(flags);}

⌨️ 快捷键说明

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