Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | /*****************************************************************************/ /* * refclock.c -- Linux soundcard HF FSK driver, * Reference clock routines. * * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch) * Swiss Federal Institute of Technology (ETH), Electronics Lab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * */ /*****************************************************************************/ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/time.h> #include <linux/hfmodem.h> #include <asm/processor.h> /* --------------------------------------------------------------------- */ /* * currently this module is supposed to support both module styles, i.e. * the old one present up to about 2.1.9, and the new one functioning * starting with 2.1.21. The reason is I have a kit allowing to compile * this module also under 2.0.x which was requested by several people. * This will go in 2.2 */ #include <linux/version.h> #if LINUX_VERSION_CODE >= 0x20123 #include <linux/init.h> #else #define __init #define __initdata #define __initfunc(x) x #endif /* --------------------------------------------------------------------- */ /* * command line params */ static unsigned int scale_tvusec = 1UL<<24; #ifdef __i386__ static unsigned int scale_rdtsc = 0; static int rdtsc_ok = 1; #endif /* __i386__ */ /* --------------------------------------------------------------------- */ #ifdef __i386__ __initfunc(static void i386_capability(void)) { if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) rdtsc_ok = 1; else printk(KERN_INFO "%s: cpu does not support the rdtsc instruction\n", hfmodem_drvname); } #endif /* __i386__ */ /* --------------------------------------------------------------------- */ __initfunc(void hfmodem_refclock_probe(void)) { #ifdef __i386__ if (rdtsc_ok) { rdtsc_ok = 0; i386_capability(); if (rdtsc_ok) { unsigned int tmp0, tmp1, tmp2, tmp3; __asm__("rdtsc" : "=a" (tmp0), "=d" (tmp1)); __asm__("rdtsc" : "=a" (tmp2), "=d" (tmp3)); if (tmp0 == tmp2 && tmp1 == tmp3) { rdtsc_ok = 0; printk(KERN_WARNING "%s: rdtsc unusable, does not change\n", hfmodem_drvname); } } } printk(KERN_INFO "%s: using %s as timing source\n", hfmodem_drvname, rdtsc_ok ? "rdtsc" : "gettimeofday"); #endif /* __i386__ */ } /* --------------------------------------------------------------------- */ void hfmodem_refclock_init(struct hfmodem_state *dev) { struct timeval tv; dev->clk.lasttime = 0; #ifdef __i386__ if (rdtsc_ok) { __asm__("rdtsc;" : "=&d" (dev->clk.starttime_hi), "=&a" (dev->clk.starttime_lo)); return; } #endif /* __i386__ */ do_gettimeofday(&tv); dev->clk.last_tvusec = tv.tv_usec; dev->clk.time_cnt = 0; } /* --------------------------------------------------------------------- */ hfmodem_time_t hfmodem_refclock_current(struct hfmodem_state *dev, hfmodem_time_t expected, int exp_valid) { struct timeval tv; hfmodem_time_t curtime; long diff; #ifdef __i386__ if (rdtsc_ok) { unsigned int tmp0, tmp1, tmp2, tmp3, tmp4; __asm__("rdtsc;\n\t" "subl %2,%%eax\n\t" "sbbl %3,%%edx\n\t" : "=&a" (tmp0), "=&d" (tmp1) : "m" (dev->clk.starttime_lo), "m" (dev->clk.starttime_hi)); __asm__("mull %2" : "=d" (tmp2), "=a" (tmp4) : "m" (scale_rdtsc), "1" (tmp0)); __asm__("mull %1" : "=a" (tmp3) : "m" (scale_rdtsc), "a" (tmp1) : "dx"); curtime = tmp2 + tmp3; goto time_known; } #endif /* __i386__ */ do_gettimeofday(&tv); dev->clk.time_cnt += (unsigned)(1000000 + tv.tv_usec - dev->clk.last_tvusec) % 1000000; dev->clk.last_tvusec = tv.tv_usec; curtime = (dev->clk.time_cnt * scale_tvusec) >> 24; time_known: if (exp_valid && abs(diff = (curtime - dev->clk.lasttime - expected)) >= 1000) printk(KERN_DEBUG "%s: refclock adjustment %ld more than 1ms\n", hfmodem_drvname, diff); return (dev->clk.lasttime = curtime); } /* --------------------------------------------------------------------- */ |