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

📄 rtc.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 2 页
字号:
		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	unsigned char tmp;	if (rtc_has_irq == 0)		goto no_irq;	/*	 * Turn off all interrupts once the device is no longer	 * in use, and clear the data.	 */	spin_lock_irq(&rtc_lock);	tmp = CMOS_READ(RTC_CONTROL);	tmp &=  ~RTC_PIE;	tmp &=  ~RTC_AIE;	tmp &=  ~RTC_UIE;	CMOS_WRITE(tmp, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	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);	}no_irq:#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;	if (rtc_has_irq == 0)		return 0;	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:		no_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){#if defined(__alpha__) || defined(__mips__)	unsigned int year, ctrl;	unsigned long uip_watchdog;	char *guess = NULL;#endif#ifdef __sparc__	struct linux_ebus *ebus;	struct linux_ebus_device *edev;#ifdef __sparc_v9__	struct isa_bridge *isa_br;	struct isa_device *isa_dev;#endif#endif#ifdef __sparc__	for_each_ebus(ebus) {		for_each_ebusdev(edev, ebus) {			if(strcmp(edev->prom_name, "rtc") == 0) {				rtc_port = edev->resource[0].start;				rtc_irq = edev->irqs[0];				goto found;			}		}	}#ifdef __sparc_v9__	for_each_isa(isa_br) {		for_each_isadev(isa_dev, isa_br) {			if (strcmp(isa_dev->prom_name, "rtc") == 0) {				rtc_port = isa_dev->resource.start;				rtc_irq = isa_dev->irq;				goto found;			}		}	}#endif	printk(KERN_ERR "rtc_init: no PC rtc found\n");	return -EIO;found:	if (rtc_irq == PCI_IRQ_NONE) {		rtc_has_irq = 0;		goto no_irq;	}	/*	 * XXX Interrupt pin #7 in Espresso is shared between RTC and	 * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here	 * is asking for trouble with add-on boards. Change to SA_SHIRQ.	 */	if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) {		/*		 * Standard way for sparc to print irq's is to use		 * __irq_itoa(). I think for EBus it's ok to use %d.		 */		printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);		return -EIO;	}no_irq:#else	if (check_region (RTC_PORT (0), RTC_IO_EXTENT))	{		printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0));		return -EIO;	}#if RTC_IRQ	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;	}#endif	request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");#endif /* __sparc__ vs. others */	misc_register(&rtc_dev);	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);#if defined(__alpha__) || defined(__mips__)	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();			cpu_relax();		}		spin_lock_irq(&rtc_lock);	year = CMOS_READ(RTC_YEAR);	ctrl = CMOS_READ(RTC_CONTROL);	spin_unlock_irq(&rtc_lock);		if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)		BCD_TO_BIN(year);       /* This should never happen... */		if (year < 20) {		epoch = 2000;		guess = "SRM (post-2000)";	} else if (year >= 20 && year < 48) {		epoch = 1980;		guess = "ARC console";	} else if (year >= 48 && year < 72) {		epoch = 1952;		guess = "Digital UNIX";#if defined(__mips__)	} else if (year >= 72 && year < 74) {		epoch = 2000;		guess = "Digital DECstation";#else	} else if (year >= 70) {		epoch = 1900;		guess = "Standard PC (1900)";#endif	}	if (guess)		printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);#endif#if RTC_IRQ	if (rtc_has_irq == 0)		goto no_irq2;	init_timer(&rtc_irq_timer);	rtc_irq_timer.function = rtc_dropped_irq;	spin_lock_irq(&rtc_lock);	/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);	spin_unlock_irq(&rtc_lock);	rtc_freq = 1024;no_irq2:#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);#ifdef __sparc__	if (rtc_has_irq)		free_irq (rtc_irq, &rtc_port);#else	release_region (RTC_PORT (0), RTC_IO_EXTENT);#if RTC_IRQ	if (rtc_has_irq)		free_irq (RTC_IRQ, NULL);#endif#endif /* __sparc__ */}module_init(rtc_init);module_exit(rtc_exit);EXPORT_NO_SYMBOLS;#if RTC_IRQ/* * 	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.) */static 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)<<8);	rtc_irq_data &= ~0xff;	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */	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){#define YN(bit) ((ctrl & bit) ? "yes" : "no")#define NY(bit) ((ctrl & bit) ? "no" : "yes")	char *p;	struct rtc_time tm;	unsigned char batt, ctrl;	unsigned long freq;	spin_lock_irq(&rtc_lock);	batt = CMOS_READ(RTC_VALID) & RTC_VRT;	ctrl = CMOS_READ(RTC_CONTROL);	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");	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",		     YN(RTC_DST_EN),		     NY(RTC_DM_BINARY),		     YN(RTC_24H),		     YN(RTC_SQWE),		     YN(RTC_AIE),		     YN(RTC_UIE),		     YN(RTC_PIE),		     freq,		     batt ? "okay" : "dead");	return  p - buf;#undef YN#undef NY}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;}/* * Returns true if a clock update is in progress *//* FIXME shouldn't this be above rtc_init to make it fully inlined? */static inline unsigned char rtc_is_updating(void){	unsigned char uip;	spin_lock_irq(&rtc_lock);	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);	spin_unlock_irq(&rtc_lock);	return uip;}static void get_rtc_time(struct rtc_time *rtc_tm){	unsigned long uip_watchdog = jiffies;	unsigned char ctrl;#ifdef CONFIG_DECSTATION	unsigned int real_year;#endif	/*	 * 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();			cpu_relax();		}	/*	 * 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 = 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);#ifdef CONFIG_DECSTATION	real_year = CMOS_READ(RTC_DEC_YEAR);#endif	ctrl = CMOS_READ(RTC_CONTROL);	spin_unlock_irq(&rtc_lock);	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);	}#ifdef CONFIG_DECSTATION	rtc_tm->tm_year += real_year - 72;#endif	/*	 * 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){	unsigned char ctrl;	/*	 * 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 = 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);	spin_unlock_irq(&rtc_lock);	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);	}}#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 char bit){	unsigned char val;	spin_lock_irq(&rtc_lock);	val = CMOS_READ(RTC_CONTROL);	val &=  ~bit;	CMOS_WRITE(val, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	rtc_irq_data = 0;	spin_unlock_irq(&rtc_lock);}static void set_rtc_irq_bit(unsigned char bit){	unsigned char val;	spin_lock_irq(&rtc_lock);	val = CMOS_READ(RTC_CONTROL);	val |= bit;	CMOS_WRITE(val, RTC_CONTROL);	CMOS_READ(RTC_INTR_FLAGS);	rtc_irq_data = 0;	spin_unlock_irq(&rtc_lock);}#endifMODULE_AUTHOR("Paul Gortmaker");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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