Changeset 8fde078 in mainline for uspace/drv/time/cmos-rtc/cmos-rtc.c
- Timestamp:
- 2012-05-22T21:57:47Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 0a0e6e7
- Parents:
- eb083ad
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/time/cmos-rtc/cmos-rtc.c
reb083ad r8fde078 38 38 #include <errno.h> 39 39 #include <ddi.h> 40 #include <as.h> 41 #include <sysinfo.h> 40 42 #include <libarch/ddi.h> 43 #include <libarch/barrier.h> 41 44 #include <stdio.h> 42 45 #include <ddf/driver.h> … … 46 49 #include <device/hw_res.h> 47 50 #include <devman.h> 51 #include <macros.h> 48 52 #include <ipc/clock_ctl.h> 49 53 … … 74 78 } rtc_t; 75 79 80 /** Pointer to the kernel shared variables with time */ 81 struct { 82 volatile sysarg_t seconds1; 83 volatile sysarg_t useconds; 84 volatile sysarg_t seconds2; 85 } *kuptime = NULL; 76 86 77 87 static int rtc_time_get(ddf_fun_t *fun, struct tm *t); … … 91 101 static int rtc_dev_remove(ddf_dev_t *dev); 92 102 static void rtc_register_write(rtc_t *rtc, int reg, int data); 103 static time_t uptime_get(void); 93 104 94 105 static ddf_dev_ops_t rtc_dev_ops; 106 static time_t boottime = 0; 95 107 96 108 /** The RTC device driver's standard operations */ … … 369 381 { 370 382 bool bcd_mode; 383 time_t norm_time; 384 time_t uptime; 371 385 int reg_b; 372 386 int reg_a; … … 375 389 376 390 /* Try to normalize the content of the tm structure */ 377 if ( mktime(t) < 0)391 if ((norm_time = mktime(t)) < 0) 378 392 return EINVAL; 393 394 uptime = uptime_get(); 395 if (norm_time <= uptime) { 396 /* This is not acceptable */ 397 return EINVAL; 398 } 399 400 /* boottime must be recomputed */ 401 boottime = 0; 379 402 380 403 fibril_mutex_lock(&rtc->mutex); … … 555 578 rtc_t *rtc = RTC_FROM_FNODE(fun); 556 579 bool batt_ok; 580 sysarg_t r = EOK; 557 581 558 582 switch (method) { … … 561 585 RTC_D_BATTERY_OK; 562 586 async_answer_1(callid, EOK, batt_ok); 587 break; 588 case CLOCK_GET_BOOTTIME: 589 if (boottime == 0) { 590 struct tm cur_tm; 591 time_t uptime; 592 593 uptime = uptime_get(); 594 r = rtc_time_get(fun, &cur_tm); 595 if (r == EOK) { 596 time_t current_time = mktime(&cur_tm); 597 if (current_time < uptime) 598 r = EINVAL; 599 else 600 boottime = current_time - uptime; 601 } 602 } 603 async_answer_1(callid, r, boottime); 563 604 break; 564 605 default: … … 635 676 } 636 677 678 /** Get the current uptime 679 * 680 * The time variables are memory mapped (read-only) from kernel which 681 * updates them periodically. 682 * 683 * As it is impossible to read 2 values atomically, we use a trick: 684 * First we read the seconds, then we read the microseconds, then we 685 * read the seconds again. If a second elapsed in the meantime, set 686 * the microseconds to zero. 687 * 688 * This assures that the values returned by two subsequent calls 689 * to gettimeofday() are monotonous. 690 * 691 */ 692 static time_t 693 uptime_get(void) 694 { 695 if (kuptime == NULL) { 696 uintptr_t faddr; 697 int rc = sysinfo_get_value("clock.faddr", &faddr); 698 if (rc != EOK) { 699 errno = rc; 700 return -1; 701 } 702 703 void *addr; 704 rc = physmem_map((void *) faddr, 1, 705 AS_AREA_READ | AS_AREA_CACHEABLE, &addr); 706 if (rc != EOK) { 707 as_area_destroy(addr); 708 errno = rc; 709 return -1; 710 } 711 712 kuptime = addr; 713 } 714 715 sysarg_t s2 = kuptime->seconds2; 716 717 read_barrier(); 718 sysarg_t s1 = kuptime->seconds1; 719 720 return max(s1, s2); 721 } 722 637 723 int 638 724 main(int argc, char **argv)
Note:
See TracChangeset
for help on using the changeset viewer.