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

📄 cmos.c

📁 Util-linux 软件包包含许多工具。其中比较重要的是加载、卸载、格式化、分区和管理硬盘驱动器
💻 C
📖 第 1 页 / 共 2 页
字号:
}static inlineunsigned long cmos_write(unsigned long reg, unsigned long val){  if (use_dev_port) {    unsigned char v = reg | 0x80;    lseek(dev_port_fd, clock_ctl_addr, 0);    write(dev_port_fd, &v, 1);    v = (val & 0xff);    lseek(dev_port_fd, clock_data_addr, 0);    write(dev_port_fd, &v, 1);  } else {    outb (reg, clock_ctl_addr);    outb (val, clock_data_addr);  }  return 0;}unsigned long cmos_set_time(unsigned long arg){  unsigned char save_control, save_freq_select, pmbit = 0;  struct tm tm = *(struct tm *) arg;  unsigned int century;/* * CMOS byte 10 (clock status register A) has 3 bitfields: * bit 7: 1 if data invalid, update in progress (read-only bit) *         (this is raised 224 us before the actual update starts) *  6-4    select base frequency *         010: 32768 Hz time base (default) *         111: reset *         all other combinations are manufacturer-dependent *         (e.g.: DS1287: 010 = start oscillator, anything else = stop) *  3-0    rate selection bits for interrupt *         0000 none (may stop RTC) *         0001, 0010 give same frequency as 1000, 1001 *         0011 122 microseconds (minimum, 8192 Hz) *         .... each increase by 1 halves the frequency, doubles the period *         1111 500 milliseconds (maximum, 2 Hz) *         0110 976.562 microseconds (default 1024 Hz) */  save_control = cmos_read (11);   /* tell the clock it's being set */  cmos_write (11, (save_control | 0x80));  save_freq_select = cmos_read (10);       /* stop and reset prescaler */  cmos_write (10, (save_freq_select | 0x70));  tm.tm_year += TM_EPOCH;  century = tm.tm_year/100;  tm.tm_year -= cmos_epoch;  tm.tm_year %= 100;  tm.tm_mon += 1;  tm.tm_wday += 1;  if (!(save_control & 0x02)) {	/* 12hr mode; the default is 24hr mode */      if (tm.tm_hour == 0)          tm.tm_hour = 24;      if (tm.tm_hour > 12) {	  tm.tm_hour -= 12;	  pmbit = 0x80;      }  }    if (!(save_control & 0x04)) { /* BCD mode - the default */      BIN_TO_BCD(tm.tm_sec);      BIN_TO_BCD(tm.tm_min);      BIN_TO_BCD(tm.tm_hour);      BIN_TO_BCD(tm.tm_wday);      BIN_TO_BCD(tm.tm_mday);      BIN_TO_BCD(tm.tm_mon);      BIN_TO_BCD(tm.tm_year);      BIN_TO_BCD(century);  }    cmos_write (0, tm.tm_sec);  cmos_write (2, tm.tm_min);  cmos_write (4, tm.tm_hour | pmbit);  cmos_write (6, tm.tm_wday);  cmos_write (7, tm.tm_mday);  cmos_write (8, tm.tm_mon);  cmos_write (9, tm.tm_year);  if (century_byte)	  cmos_write (century_byte, century);    /* The kernel sources, linux/arch/i386/kernel/time.c, have the       following comment:           The following flags have to be released exactly in this order,       otherwise the DS12887 (popular MC146818A clone with integrated       battery and quartz) will not reset the oscillator and will not       update precisely 500 ms later.  You won't find this mentioned       in the Dallas Semiconductor data sheets, but who believes data       sheets anyway ...  -- Markus Kuhn    */      cmos_write (11, save_control);  cmos_write (10, save_freq_select);  return 0;}static inthclock_read(unsigned long reg) {	return atomic("clock read", cmos_read, (reg));}static voidhclock_set_time(const struct tm *tm) {	atomic("set time", cmos_set_time, (unsigned long)(tm));}static inline intcmos_clock_busy(void) {	return#ifdef __alpha__	                /* poll bit 4 (UF) of Control Register C */	    funkyTOY ? (hclock_read(12) & 0x10) :#endif		        /* poll bit 7 (UIP) of Control Register A */	    (hclock_read(10) & 0x80);}static intsynchronize_to_clock_tick_cmos(void) {  int i;  /* Wait for rise.  Should be within a second, but in case something     weird happens, we have a limit on this loop to reduce the impact     of this failure.     */  for (i = 0; !cmos_clock_busy(); i++)	  if (i >= 10000000)		  return 1;  /* Wait for fall.  Should be within 2.228 ms. */  for (i = 0; cmos_clock_busy(); i++)	  if (i >= 1000000)		  return 1;  return 0;}static intread_hardware_clock_cmos(struct tm *tm) {/*----------------------------------------------------------------------------  Read the hardware clock and return the current time via <tm> argument.  Assume we have an ISA machine and read the clock directly with CPU I/O  instructions.  This function is not totally reliable.  It takes a finite and  unpredictable amount of time to execute the code below.  During that  time, the clock may change and we may even read an invalid value in  the middle of an update.  We do a few checks to minimize this  possibility, but only the kernel can actually read the clock  properly, since it can execute code in a short and predictable  amount of time (by turning of interrupts).  In practice, the chance of this function returning the wrong time is  extremely remote.-----------------------------------------------------------------------------*/  bool got_time = FALSE;  unsigned char status, pmbit;  status = pmbit = 0;		/* just for gcc */  while (!got_time) {    /* Bit 7 of Byte 10 of the Hardware Clock value is the Update In Progress       (UIP) bit, which is on while and 244 uS before the Hardware Clock        updates itself.  It updates the counters individually, so reading        them during an update would produce garbage.  The update takes 2mS,       so we could be spinning here that long waiting for this bit to turn       off.       Furthermore, it is pathologically possible for us to be in this       code so long that even if the UIP bit is not on at first, the       clock has changed while we were running.  We check for that too,       and if it happens, we start over.       */    if (!cmos_clock_busy()) {      /* No clock update in progress, go ahead and read */      tm->tm_sec = hclock_read(0);      tm->tm_min = hclock_read(2);      tm->tm_hour = hclock_read(4);      tm->tm_wday = hclock_read(6);      tm->tm_mday = hclock_read(7);      tm->tm_mon = hclock_read(8);      tm->tm_year = hclock_read(9);      status = hclock_read(11);#if 0      if (century_byte)	  century = hclock_read(century_byte);#endif      /* Unless the clock changed while we were reading, consider this          a good clock read .       */      if (tm->tm_sec == hclock_read (0))	got_time = TRUE;    }    /* Yes, in theory we could have been running for 60 seconds and       the above test wouldn't work!       */  }  if (!(status & 0x04)) { /* BCD mode - the default */      BCD_TO_BIN(tm->tm_sec);      BCD_TO_BIN(tm->tm_min);      pmbit = (tm->tm_hour & 0x80);      tm->tm_hour &= 0x7f;      BCD_TO_BIN(tm->tm_hour);      BCD_TO_BIN(tm->tm_wday);      BCD_TO_BIN(tm->tm_mday);      BCD_TO_BIN(tm->tm_mon);      BCD_TO_BIN(tm->tm_year);#if 0      BCD_TO_BIN(century);#endif  }  /* We don't use the century byte of the Hardware Clock     since we don't know its address (usually 50 or 55).     Here, we follow the advice of the X/Open Base Working Group:     "if century is not specified, then values in the range [69-99]      refer to years in the twentieth century (1969 to 1999 inclusive),      and values in the range [00-68] refer to years in the twenty-first      century (2000 to 2068 inclusive)."   */  tm->tm_wday -= 1;  tm->tm_mon -= 1;  tm->tm_year += (cmos_epoch - TM_EPOCH);  if (tm->tm_year < 69)	  tm->tm_year += 100;  if (pmbit) {	  tm->tm_hour += 12;	  if (tm->tm_hour == 24)		  tm->tm_hour = 0;  }  tm->tm_isdst = -1;        /* don't know whether it's daylight */  return 0;}static intset_hardware_clock_cmos(const struct tm *new_broken_time) {    hclock_set_time(new_broken_time);    return 0;}static inti386_iopl(const int level) {#if defined(__i386__) || defined(__alpha__)  extern int iopl(const int lvl);  return iopl(level);#else  return -2;#endif}static intget_permissions_cmos(void) {  int rc;  if (use_dev_port) {    if ((dev_port_fd = open("/dev/port", O_RDWR)) < 0) {      int errsv = errno;      fprintf(stderr, _("Cannot open /dev/port: %s"), strerror(errsv));      rc = 1;    } else      rc = 0;  } else {    rc = i386_iopl(3);    if (rc == -2) {      fprintf(stderr, _("I failed to get permission because I didn't try.\n"));    } else if (rc != 0) {      rc = errno;      fprintf(stderr, _("%s is unable to get I/O port access:  "              "the iopl(3) call failed.\n"), progname);      if(rc == EPERM && geteuid())        fprintf(stderr, _("Probably you need root privileges.\n"));    }  }  return rc ? 1 : 0;}static struct clock_ops cmos = {	"direct I/O instructions to ISA clock",	get_permissions_cmos,	read_hardware_clock_cmos,	set_hardware_clock_cmos,	synchronize_to_clock_tick_cmos,};/* return &cmos if cmos clock present, NULL otherwise *//* choose this construction to avoid gcc messages about unused variables */struct clock_ops *probe_for_cmos_clock(void){    int have_cmos =#if defined(__i386__) || defined(__alpha__)	    TRUE;#else	    FALSE;#endif    return have_cmos ? &cmos : NULL;}

⌨️ 快捷键说明

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