Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * This code largely moved from arch/i386/kernel/time.c.
  3  * See comments there for proper credits.
  4  */
  5 
  6 #include <linux/spinlock.h>
  7 #include <linux/module.h>
  8 #include <linux/device.h>
  9 #include <linux/irq.h>
 10 #include <linux/sysdev.h>
 11 #include <linux/timex.h>
 12 #include <asm/delay.h>
 13 #include <asm/mpspec.h>
 14 #include <asm/timer.h>
 15 #include <asm/smp.h>
 16 #include <asm/io.h>
 17 #include <asm/arch_hooks.h>
 18 
 19 extern spinlock_t i8259A_lock;
 20 extern spinlock_t i8253_lock;
 21 #include "do_timer.h"
 22 #include "io_ports.h"
 23 
 24 static int count_p; /* counter in get_offset_pit() */
 25 
 26 static int __init init_pit(char* override)
 27 {
 28         /* check clock override */
 29         if (override[0] && strncmp(override,"pit",3))
 30                 printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
 31  
 32         count_p = LATCH;
 33         return 0;
 34 }
 35 
 36 static void mark_offset_pit(void)
 37 {
 38         /* nothing needed */
 39 }
 40 
 41 static unsigned long long monotonic_clock_pit(void)
 42 {
 43         return 0;
 44 }
 45 
 46 static void delay_pit(unsigned long loops)
 47 {
 48         int d0;
 49         __asm__ __volatile__(
 50                 "\tjmp 1f\n"
 51                 ".align 16\n"
 52                 "1:\tjmp 2f\n"
 53                 ".align 16\n"
 54                 "2:\tdecl %0\n\tjns 2b"
 55                 :"=&a" (d0)
 56                 :"" (loops));
 57 }
 58 
 59 
 60 /* This function must be called with xtime_lock held.
 61  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
 62  * 
 63  * However, the pc-audio speaker driver changes the divisor so that
 64  * it gets interrupted rather more often - it loads 64 into the
 65  * counter rather than 11932! This has an adverse impact on
 66  * do_gettimeoffset() -- it stops working! What is also not
 67  * good is that the interval that our timer function gets called
 68  * is no longer 10.0002 ms, but 9.9767 ms. To get around this
 69  * would require using a different timing source. Maybe someone
 70  * could use the RTC - I know that this can interrupt at frequencies
 71  * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
 72  * it so that at startup, the timer code in sched.c would select
 73  * using either the RTC or the 8253 timer. The decision would be
 74  * based on whether there was any other device around that needed
 75  * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
 76  * and then do some jiggery to have a version of do_timer that 
 77  * advanced the clock by 1/1024 s. Every time that reached over 1/100
 78  * of a second, then do all the old code. If the time was kept correct
 79  * then do_gettimeoffset could just return 0 - there is no low order
 80  * divider that can be accessed.
 81  *
 82  * Ideally, you would be able to use the RTC for the speaker driver,
 83  * but it appears that the speaker driver really needs interrupt more
 84  * often than every 120 us or so.
 85  *
 86  * Anyway, this needs more thought....          pjsg (1993-08-28)
 87  * 
 88  * If you are really that interested, you should be reading
 89  * comp.protocols.time.ntp!
 90  */
 91 
 92 static unsigned long get_offset_pit(void)
 93 {
 94         int count;
 95         unsigned long flags;
 96         static unsigned long jiffies_p = 0;
 97 
 98         /*
 99          * cache volatile jiffies temporarily; we have xtime_lock. 
100          */
101         unsigned long jiffies_t;
102 
103         spin_lock_irqsave(&i8253_lock, flags);
104         /* timer count may underflow right here */
105         outb_p(0x00, PIT_MODE); /* latch the count ASAP */
106 
107         count = inb_p(PIT_CH0); /* read the latched count */
108 
109         /*
110          * We do this guaranteed double memory access instead of a _p 
111          * postfix in the previous port access. Wheee, hackady hack
112          */
113         jiffies_t = jiffies;
114 
115         count |= inb_p(PIT_CH0) << 8;
116         
117         /* VIA686a test code... reset the latch if count > max + 1 */
118         if (count > LATCH) {
119                 outb_p(0x34, PIT_MODE);
120                 outb_p(LATCH & 0xff, PIT_CH0);
121                 outb(LATCH >> 8, PIT_CH0);
122                 count = LATCH - 1;
123         }
124         
125         /*
126          * avoiding timer inconsistencies (they are rare, but they happen)...
127          * there are two kinds of problems that must be avoided here:
128          *  1. the timer counter underflows
129          *  2. hardware problem with the timer, not giving us continuous time,
130          *     the counter does small "jumps" upwards on some Pentium systems,
131          *     (see c't 95/10 page 335 for Neptun bug.)
132          */
133 
134         if( jiffies_t == jiffies_p ) {
135                 if( count > count_p ) {
136                         /* the nutcase */
137                         count = do_timer_overflow(count);
138                 }
139         } else
140                 jiffies_p = jiffies_t;
141 
142         count_p = count;
143 
144         spin_unlock_irqrestore(&i8253_lock, flags);
145 
146         count = ((LATCH-1) - count) * TICK_SIZE;
147         count = (count + LATCH/2) / LATCH;
148 
149         return count;
150 }
151 
152 
153 /* tsc timer_opts struct */
154 struct timer_opts timer_pit = {
155         .name = "pit",
156         .mark_offset = mark_offset_pit, 
157         .get_offset = get_offset_pit,
158         .monotonic_clock = monotonic_clock_pit,
159         .delay = delay_pit,
160 };
161 
162 struct init_timer_opts __initdata timer_pit_init = {
163         .init = init_pit, 
164         .opts = &timer_pit,
165 };
166 
167 void setup_pit_timer(void)
168 {
169         extern spinlock_t i8253_lock;
170         unsigned long flags;
171 
172         spin_lock_irqsave(&i8253_lock, flags);
173         outb_p(0x34,PIT_MODE);          /* binary, mode 2, LSB/MSB, ch 0 */
174         udelay(10);
175         outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
176         udelay(10);
177         outb(LATCH >> 8 , PIT_CH0);     /* MSB */
178         spin_unlock_irqrestore(&i8253_lock, flags);
179 }
180 
181 static int timer_resume(struct sys_device *dev)
182 {
183         setup_pit_timer();
184         return 0;
185 }
186 
187 static struct sysdev_class timer_sysclass = {
188         set_kset_name("timer_pit"),
189         .resume = timer_resume,
190 };
191 
192 static struct sys_device device_timer = {
193         .id     = 0,
194         .cls    = &timer_sysclass,
195 };
196 
197 static int __init init_timer_sysfs(void)
198 {
199         int error = sysdev_class_register(&timer_sysclass);
200         if (!error)
201                 error = sysdev_register(&device_timer);
202         return error;
203 }
204 
205 device_initcall(init_timer_sysfs);
206 
207 
  This page was automatically generated by the LXR engine.