diff --git a/config/os/gnu-linux/time.c b/config/os/gnu-linux/time.c index 923597a..72e2aa4 100644 --- a/config/os/gnu-linux/time.c +++ b/config/os/gnu-linux/time.c @@ -22,28 +22,37 @@ #include +#include + static jack_time_t __jack_cpu_mhz = 0; jack_time_t (*_jack_get_microseconds)(void) = 0; #if defined(__gnu_linux__) && (defined(__i386__) || defined(__x86_64__)) #define HPET_SUPPORT -#define HPET_MMAP_SIZE 1024 -#define HPET_PERIOD 0x004 -#define HPET_COUNTER 0x0f0 +#define HPET_MMAP_SIZE 1024 +#define HPET_CAPS 0x000 +#define HPET_PERIOD 0x004 +#define HPET_COUNTER 0x0f0 +#define HPET_CAPS_COUNTER_64BIT (1 << 13) #if defined(__x86_64__) -#define HPET_64BIT +typedef uint64_t hpet_counter_t; #else -#define HPET_32BIT +typedef uint32_t hpet_counter_t; #endif static int hpet_fd; static unsigned char *hpet_ptr; -static unsigned int hpet_period; /* period length in femto secs */ +static uint32_t hpet_period; /* period length in femto secs */ +static uint64_t hpet_offset = 0; +static uint64_t hpet_wrap; +static hpet_counter_t hpet_previous = 0; #endif /* defined(__gnu_linux__) && (__i386__ || __x86_64__) */ #ifdef HPET_SUPPORT int jack_hpet_init () { + uint32_t hpet_caps; + hpet_fd = open("/dev/hpet", O_RDONLY); if (hpet_fd < 0) { jack_error ("This system has no accessible HPET device (%s)", strerror (errno)); @@ -61,28 +70,27 @@ jack_hpet_init () /* this assumes period to be constant. if needed, it can be moved to the clock access function */ + hpet_period = *((uint32_t *) (hpet_ptr + HPET_PERIOD)); + hpet_caps = *((uint32_t *) (hpet_ptr + HPET_CAPS)); + hpet_wrap = ((hpet_caps & HPET_CAPS_COUNTER_64BIT) && + (sizeof(hpet_counter_t) == sizeof(uint64_t))) ? + 0 : ((uint64_t) 1 << 32); - hpet_period = *((unsigned int *) (hpet_ptr + HPET_PERIOD)); return 0; } static jack_time_t jack_get_microseconds_from_hpet (void) { -#ifdef HPET_64BIT - unsigned long long hpet_counter; -#else - unsigned int hpet_counter; -#endif + hpet_counter_t hpet_counter; long double hpet_time; -#ifdef HPET_64BIT - hpet_counter = *((unsigned long long *) (hpet_ptr + HPET_COUNTER)); -#else - hpet_counter = *((unsigned int *) (hpet_ptr + HPET_COUNTER)); -#endif - hpet_time = (long double) hpet_counter * (long double) hpet_period * - (long double) 1e-9; + hpet_counter = *((hpet_counter_t *) (hpet_ptr + HPET_COUNTER)); + if (unlikely(hpet_counter < hpet_previous)) + hpet_offset += hpet_wrap; + hpet_previous = hpet_counter; + hpet_time = (long double) (hpet_offset + hpet_counter) * + (long double) hpet_period * (long double) 1e-9; return ((jack_time_t) (hpet_time + 0.5)); }