time.c

来自「linux 内核源代码」· C语言 代码 · 共 603 行 · 第 1/2 页

C
603
字号
{	struct device_node *dp = op->node;	const char *model = of_get_property(dp, "model", NULL);	if (!model)		return -ENODEV;	if (!strcmp(model, "mk48t02")) {		sp_clock_typ = MSTK48T02;		/* Map the clock register io area read-only */		mstk48t02_regs = of_ioremap(&op->resource[0], 0,					    sizeof(struct mostek48t02),					    "mk48t02");		mstk48t08_regs = NULL;  /* To catch weirdness */	} else if (!strcmp(model, "mk48t08")) {		sp_clock_typ = MSTK48T08;		mstk48t08_regs = of_ioremap(&op->resource[0], 0,					    sizeof(struct mostek48t08),					    "mk48t08");		mstk48t02_regs = &mstk48t08_regs->regs;	} else		return -ENODEV;	/* Report a low battery voltage condition. */	if (has_low_battery())		printk(KERN_CRIT "NVRAM: Low battery voltage!\n");	/* Kick start the clock if it is completely stopped. */	if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)		kick_start_clock();	mostek_set_system_time();	return 0;}static struct of_device_id clock_match[] = {	{		.name = "eeprom",	},	{},};static struct of_platform_driver clock_driver = {	.match_table	= clock_match,	.probe		= clock_probe,	.driver		= {		.name	= "clock",	},};/* Probe for the mostek real time clock chip. */static int __init clock_init(void){	return of_register_driver(&clock_driver, &of_platform_bus_type);}/* Must be after subsys_initcall() so that busses are probed.  Must * be before device_initcall() because things like the RTC driver * need to see the clock registers. */fs_initcall(clock_init);#endif /* !CONFIG_SUN4 */void __init sbus_time_init(void){	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);	btfixup();	if (ARCH_SUN4)		sun4_clock_probe();	sparc_init_timers(timer_interrupt);	#ifdef CONFIG_SUN4	if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {		mostek_set_system_time();	} else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {		/* initialise the intersil on sun4 */		unsigned int year, mon, day, hour, min, sec;		int temp;		struct intersil *iregs;		iregs=intersil_clock;		if(!iregs) {			prom_printf("Something wrong, clock regs not mapped yet.\n");			prom_halt();		}		intersil_intr(intersil_clock,INTERSIL_INT_100HZ);		disable_pil_irq(10);		intersil_stop(iregs);		intersil_read_intr(intersil_clock, temp);		temp = iregs->clk.int_csec;		sec = iregs->clk.int_sec;		min = iregs->clk.int_min;		hour = iregs->clk.int_hour;		day = iregs->clk.int_day;		mon = iregs->clk.int_month;		year = MSTK_CVT_YEAR(iregs->clk.int_year);		enable_pil_irq(10);		intersil_start(iregs);		xtime.tv_sec = mktime(year, mon, day, hour, min, sec);		xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);	        set_normalized_timespec(&wall_to_monotonic, 	                               -xtime.tv_sec, -xtime.tv_nsec);		printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);	}#endif	/* Now that OBP ticker has been silenced, it is safe to enable IRQ. */	local_irq_enable();}void __init time_init(void){#ifdef CONFIG_PCI	extern void pci_time_init(void);	if (pcic_present()) {		pci_time_init();		return;	}#endif	sbus_time_init();}static inline unsigned long do_gettimeoffset(void){	unsigned long val = *master_l10_counter;	unsigned long usec = (val >> 10) & 0x1fffff;	/* Limit hit?  */	if (val & 0x80000000)		usec += 1000000 / HZ;	return usec;}/* Ok, my cute asm atomicity trick doesn't work anymore. * There are just too many variables that need to be protected * now (both members of xtime, et al.) */void do_gettimeofday(struct timeval *tv){	unsigned long flags;	unsigned long seq;	unsigned long usec, sec;	unsigned long max_ntp_tick = tick_usec - tickadj;	do {		seq = read_seqbegin_irqsave(&xtime_lock, flags);		usec = do_gettimeoffset();		/*		 * If time_adjust is negative then NTP is slowing the clock		 * so make sure not to go into next possible interval.		 * Better to lose some accuracy than have time go backwards..		 */		if (unlikely(time_adjust < 0))			usec = min(usec, max_ntp_tick);		sec = xtime.tv_sec;		usec += (xtime.tv_nsec / 1000);	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));	while (usec >= 1000000) {		usec -= 1000000;		sec++;	}	tv->tv_sec = sec;	tv->tv_usec = usec;}EXPORT_SYMBOL(do_gettimeofday);int do_settimeofday(struct timespec *tv){	int ret;	write_seqlock_irq(&xtime_lock);	ret = bus_do_settimeofday(tv);	write_sequnlock_irq(&xtime_lock);	clock_was_set();	return ret;}EXPORT_SYMBOL(do_settimeofday);static int sbus_do_settimeofday(struct timespec *tv){	time_t wtm_sec, sec = tv->tv_sec;	long wtm_nsec, nsec = tv->tv_nsec;	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)		return -EINVAL;	/*	 * This is revolting. We need to set "xtime" correctly. However, the	 * value in this location is the value at the most recent update of	 * wall time.  Discover what correction gettimeofday() would have	 * made, and then undo it!	 */	nsec -= 1000 * do_gettimeoffset();	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);	set_normalized_timespec(&xtime, sec, nsec);	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);	ntp_clear();	return 0;}/* * BUG: This routine does not handle hour overflow properly; it just *      sets the minutes. Usually you won't notice until after reboot! */static int set_rtc_mmss(unsigned long nowtime){	int real_seconds, real_minutes, mostek_minutes;	struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;	unsigned long flags;#ifdef CONFIG_SUN4	struct intersil *iregs = intersil_clock;	int temp;#endif	/* Not having a register set can lead to trouble. */	if (!regs) {#ifdef CONFIG_SUN4		if(!iregs)		return -1;	 	else {			temp = iregs->clk.int_csec;			mostek_minutes = iregs->clk.int_min;			real_seconds = nowtime % 60;			real_minutes = nowtime / 60;			if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)				real_minutes += 30;	/* correct for half hour time zone */			real_minutes %= 60;			if (abs(real_minutes - mostek_minutes) < 30) {				intersil_stop(iregs);				iregs->clk.int_sec=real_seconds;				iregs->clk.int_min=real_minutes;				intersil_start(iregs);			} else {				printk(KERN_WARNING			       "set_rtc_mmss: can't update from %d to %d\n",				       mostek_minutes, real_minutes);				return -1;			}						return 0;		}#endif	}	spin_lock_irqsave(&mostek_lock, flags);	/* Read the current RTC minutes. */	regs->creg |= MSTK_CREG_READ;	mostek_minutes = MSTK_REG_MIN(regs);	regs->creg &= ~MSTK_CREG_READ;	/*	 * since we're only adjusting minutes and seconds,	 * don't interfere with hour overflow. This avoids	 * messing with unknown time zones but requires your	 * RTC not to be off by more than 15 minutes	 */	real_seconds = nowtime % 60;	real_minutes = nowtime / 60;	if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)		real_minutes += 30;	/* correct for half hour time zone */	real_minutes %= 60;	if (abs(real_minutes - mostek_minutes) < 30) {		regs->creg |= MSTK_CREG_WRITE;		MSTK_SET_REG_SEC(regs,real_seconds);		MSTK_SET_REG_MIN(regs,real_minutes);		regs->creg &= ~MSTK_CREG_WRITE;		spin_unlock_irqrestore(&mostek_lock, flags);		return 0;	} else {		spin_unlock_irqrestore(&mostek_lock, flags);		return -1;	}}

⌨️ 快捷键说明

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