Changeset 8fde078 in mainline for uspace/drv/time/cmos-rtc/cmos-rtc.c


Ignore:
Timestamp:
2012-05-22T21:57:47Z (13 years ago)
Author:
Maurizio Lombardi <m.lombardi85@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0a0e6e7
Parents:
eb083ad
Message:

rtc: add support to the CLOCK_GET_BOOTTIME request

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/time/cmos-rtc/cmos-rtc.c

    reb083ad r8fde078  
    3838#include <errno.h>
    3939#include <ddi.h>
     40#include <as.h>
     41#include <sysinfo.h>
    4042#include <libarch/ddi.h>
     43#include <libarch/barrier.h>
    4144#include <stdio.h>
    4245#include <ddf/driver.h>
     
    4649#include <device/hw_res.h>
    4750#include <devman.h>
     51#include <macros.h>
    4852#include <ipc/clock_ctl.h>
    4953
     
    7478} rtc_t;
    7579
     80/** Pointer to the kernel shared variables with time */
     81struct {
     82        volatile sysarg_t seconds1;
     83        volatile sysarg_t useconds;
     84        volatile sysarg_t seconds2;
     85} *kuptime = NULL;
    7686
    7787static int  rtc_time_get(ddf_fun_t *fun, struct tm *t);
     
    91101static int rtc_dev_remove(ddf_dev_t *dev);
    92102static void rtc_register_write(rtc_t *rtc, int reg, int data);
     103static time_t uptime_get(void);
    93104
    94105static ddf_dev_ops_t rtc_dev_ops;
     106static time_t boottime = 0;
    95107
    96108/** The RTC device driver's standard operations */
     
    369381{
    370382        bool bcd_mode;
     383        time_t norm_time;
     384        time_t uptime;
    371385        int  reg_b;
    372386        int  reg_a;
     
    375389
    376390        /* Try to normalize the content of the tm structure */
    377         if (mktime(t) < 0)
     391        if ((norm_time = mktime(t)) < 0)
    378392                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;
    379402
    380403        fibril_mutex_lock(&rtc->mutex);
     
    555578        rtc_t *rtc = RTC_FROM_FNODE(fun);
    556579        bool batt_ok;
     580        sysarg_t r = EOK;
    557581
    558582        switch (method) {
     
    561585                    RTC_D_BATTERY_OK;
    562586                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);
    563604                break;
    564605        default:
     
    635676}
    636677
     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 */
     692static time_t
     693uptime_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
    637723int
    638724main(int argc, char **argv)
Note: See TracChangeset for help on using the changeset viewer.