time.c
来自「底层驱动开发」· C语言 代码 · 共 638 行 · 第 1/2 页
C
638 行
if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { prom_printf("clock_probe: FAILED!\n"); prom_halt(); } if (sparc_cpu_model == sun4d) prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ r.flags = clk_reg[0].which_io; r.start = clk_reg[0].phys_addr; mstk48t02_regs = sbus_ioremap(&r, 0, sizeof(struct mostek48t02), "mk48t02"); mstk48t08_regs = NULL; /* To catch weirdness */ } else if (strcmp(model, "mk48t08") == 0) { sp_clock_typ = MSTK48T08; if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { prom_printf("clock_probe: FAILED!\n"); prom_halt(); } if (sparc_cpu_model == sun4d) prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); else prom_apply_obio_ranges(clk_reg, 1); /* Map the clock register io area read-only */ /* XXX r/o attribute is somewhere in r.flags */ r.flags = clk_reg[0].which_io; r.start = clk_reg[0].phys_addr; mstk48t08_regs = (struct mostek48t08 *) sbus_ioremap(&r, 0, sizeof(struct mostek48t08), "mk48t08"); mstk48t02_regs = &mstk48t08_regs->regs; } else { prom_printf("CLOCK: Unknown model name '%s'\n",model); prom_halt(); } /* 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();}void __init sbus_time_init(void){ unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs;#ifdef CONFIG_SUN4 int temp; struct intersil *iregs;#endif BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); btfixup(); if (ARCH_SUN4) sun4_clock_probe(); else clock_probe(); sparc_init_timers(timer_interrupt); #ifdef CONFIG_SUN4 if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {#endif mregs = (struct mostek48t02 *)mstk48t02_regs; if(!mregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); prom_halt(); } spin_lock_irq(&mostek_lock); mregs->creg |= MSTK_CREG_READ; sec = MSTK_REG_SEC(mregs); min = MSTK_REG_MIN(mregs); hour = MSTK_REG_HOUR(mregs); day = MSTK_REG_DOM(mregs); mon = MSTK_REG_MONTH(mregs); year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); 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); mregs->creg &= ~MSTK_CREG_READ; spin_unlock_irq(&mostek_lock);#ifdef CONFIG_SUN4 } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) { /* initialise the intersil on sun4 */ 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){ return (*master_l10_counter >> 10) & 0x1fffff;}/* * Returns nanoseconds * XXX This is a suboptimal implementation. */unsigned long long sched_clock(void){ return (unsigned long long)jiffies * (1000000000 / HZ);}/* 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, wall_jiffies, 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 { unsigned long lost; seq = read_seqbegin_irqsave(&xtime_lock, flags); usec = do_gettimeoffset(); lost = jiffies - wall_jiffies; /* * 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); if (lost) usec += lost * max_ntp_tick; } else if (unlikely(lost)) usec += lost * tick_usec; 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() + (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ)); 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 + -
显示快捷键?