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 + -
显示快捷键?