base/arch/i386/hal/rtc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005-2008  Paolo Mantegazza  (mantegazza@aero.polimi.it)
00003  * (RTC specific part with) Giuseppe Quaranta (quaranta@aero.polimi.it)
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License as
00007  * published by the Free Software Foundation; either version 2 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018  */
00019 
00020 
00021 #ifdef INCLUDED_BY_HAL_C
00022 
00023 #include <linux/mc146818rtc.h>
00024 static inline unsigned char RT_CMOS_READ(unsigned char addr)
00025 {
00026     outb_p(addr, RTC_PORT(0));
00027     return inb_p(RTC_PORT(1));
00028 }
00029 
00030 //#define TEST_RTC
00031 #define MIN_RTC_FREQ  2
00032 #define MAX_RTC_FREQ  8192
00033 #define RTC_FREQ      MAX_RTC_FREQ
00034 
00035 static void rt_broadcast_rtc_interrupt(void)
00036 {
00037 #ifdef CONFIG_SMP
00038     apic_wait_icr_idle();
00039     apic_write_around(APIC_ICR, APIC_DM_FIXED | APIC_DEST_ALLBUT | RTAI_APIC_TIMER_VECTOR | APIC_DEST_LOGICAL);
00040     ((void (*)(void))rtai_realtime_irq[RTAI_APIC_TIMER_IPI].handler)();
00041 #endif
00042 }
00043 
00044 static void (*usr_rtc_handler)(void);
00045 
00046 #if CONFIG_RTAI_DONT_DISPATCH_CORE_IRQS
00047 
00048 int _rtai_rtc_timer_handler(void)
00049 {
00050     unsigned long cpuid = rtai_cpuid();
00051     unsigned long sflags;
00052 
00053     HAL_LOCK_LINUX();
00054     rt_mask_and_ack_irq(RTC_IRQ);
00055     RTAI_SCHED_ISR_LOCK();
00056 
00057     RT_CMOS_READ(RTC_INTR_FLAGS); // CMOS_READ(RTC_INTR_FLAGS);
00058     rt_enable_irq(RTC_IRQ);
00059     usr_rtc_handler();
00060 
00061     RTAI_SCHED_ISR_UNLOCK();
00062     HAL_UNLOCK_LINUX();
00063 
00064     if (!test_bit(IPIPE_STALL_FLAG, ROOT_STATUS_ADR(cpuid))) {
00065         rtai_sti();
00066         hal_fast_flush_pipeline(cpuid);
00067 #if defined(CONFIG_SMP) &&  LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,32)
00068         __set_bit(IPIPE_STALL_FLAG, ROOT_STATUS_ADR(cpuid));
00069 #endif
00070         return 1;
00071     }
00072 
00073     return 0;
00074 }
00075 
00076 void rtai_rtc_timer_handler(void);
00077 DEFINE_VECTORED_ISR(rtai_rtc_timer_handler, _rtai_rtc_timer_handler);
00078 
00079 static struct desc_struct rtai_rtc_timer_sysvec;
00080 
00081 #endif /* CONFIG_RTAI_DONT_DISPATCH_CORE_IRQS */
00082 
00083 /* 
00084  * NOTE FOR USE IN RTAI_TRIOSS.
00085  * "rtc_freq" must be a power of 2 & (MIN_RTC_FREQ <= rtc_freq <= MAX_RTC_FREQ).
00086  * So the best thing to do is to load this module and your skin of choice 
00087  * setting "rtc_freq" in this module and "rtc_freq" in the skin specific module
00088  * to the very same power of 2 that best fits your needs.
00089  */ 
00090 
00091 static void rtc_handler(int irq, int rtc_freq)
00092 {
00093 #ifdef TEST_RTC
00094     static int stp, cnt;
00095     if (++cnt == rtc_freq) {
00096         rt_printk("<> IRQ %d, %d: CNT %d <>\n", irq, ++stp, cnt);
00097         cnt = 0;
00098     }
00099 #endif
00100     RT_CMOS_READ(RTC_INTR_FLAGS); // CMOS_READ(RTC_INTR_FLAGS);
00101     rt_enable_irq(RTC_IRQ);
00102     if (usr_rtc_handler) {
00103         usr_rtc_handler();
00104     }
00105 }
00106 
00107 int fusion_timer_running;
00108 #ifdef RTAI_TRIOSS
00109 static void fusion_rtc_handler(void)
00110 {
00111 #ifdef CONFIG_X86_LOCAL_APIC
00112 #include <asm/apic.h>
00113 #include <mach_ipi.h>
00114     int cpuid;
00115     for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) {
00116         hal_pend_domain_uncond(RTAI_APIC_TIMER_VECTOR, fusion_domain, cpuid);
00117     }
00118 #ifdef CONFIG_SMP
00119     send_IPI_allbutself(RESCHEDULE_VECTOR);  // any unharmful ipi suffices 
00120 #endif
00121 #else 
00122     hal_pend_domain_uncond(RTAI_TIMER_8254_IRQ, fusion_domain, rtai_cpuid());
00123 #endif
00124 }
00125 EXPORT_SYMBOL(fusion_timer_running);
00126 #endif
00127 
00128 void rt_request_rtc(long rtc_freq, void *handler)
00129 {
00130     int pwr2;
00131 
00132     if (rtc_freq <= 0) {
00133         rtc_freq = RTC_FREQ;
00134     }
00135     if (rtc_freq > MAX_RTC_FREQ) {
00136         rtc_freq = MAX_RTC_FREQ;
00137     } else if (rtc_freq < MIN_RTC_FREQ) {
00138         rtc_freq = MIN_RTC_FREQ;
00139     }
00140     pwr2 = 1;
00141     if (rtc_freq > MIN_RTC_FREQ) {
00142         while (rtc_freq > (1 << pwr2)) {
00143             pwr2++;
00144         }
00145         if (rtc_freq <= ((3*(1 << (pwr2 - 1)) + 1)>>1)) {
00146             pwr2--;
00147         }
00148     }
00149 
00150     rt_disable_irq(RTC_IRQ);
00151     rt_release_irq(RTC_IRQ);
00152     rtai_cli();
00153     CMOS_WRITE(CMOS_READ(RTC_FREQ_SELECT), RTC_FREQ_SELECT);
00154     CMOS_WRITE(CMOS_READ(RTC_CONTROL),     RTC_CONTROL);
00155     CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - pwr2),          RTC_FREQ_SELECT);
00156     CMOS_WRITE((CMOS_READ(RTC_CONTROL) & 0x8F) | RTC_PIE, RTC_CONTROL);
00157     rtai_sti();
00158 #ifdef RTAI_TRIOSS
00159     usr_rtc_handler = fusion_rtc_handler;
00160 #else
00161     usr_rtc_handler = handler ? handler : rt_broadcast_rtc_interrupt;
00162 #endif
00163     SET_FUSION_TIMER_RUNNING();
00164 #ifdef TEST_RTC
00165     rt_printk("<%s>\n", fusion_timer_running ? "FUSION TIMER RUNNING" : "");
00166 #endif
00167     rt_request_irq(RTC_IRQ, (void *)rtc_handler, (void *)rtc_freq, 0);
00168     SET_INTR_GATE(ext_irq_vector(RTC_IRQ), rtai_rtc_timer_handler, rtai_rtc_timer_sysvec);
00169     rt_enable_irq(RTC_IRQ);
00170     CMOS_READ(RTC_INTR_FLAGS);
00171     return;
00172 }
00173 
00174 void rt_release_rtc(void)
00175 {
00176     rt_disable_irq(RTC_IRQ);
00177     usr_rtc_handler = NULL;
00178     CLEAR_FUSION_TIMER_RUNNING();
00179     RESET_INTR_GATE(ext_irq_vector(RTC_IRQ), rtai_rtc_timer_sysvec);
00180     rt_release_irq(RTC_IRQ);
00181     rtai_cli();
00182     CMOS_WRITE(CMOS_READ(RTC_FREQ_SELECT), RTC_FREQ_SELECT);
00183     CMOS_WRITE(CMOS_READ(RTC_CONTROL),     RTC_CONTROL);
00184     rtai_sti();
00185     return;
00186 }
00187 
00188 EXPORT_SYMBOL(rt_request_rtc);
00189 EXPORT_SYMBOL(rt_release_rtc);
00190 
00191 #endif /* INCLUDED_BY_HAL_C */
00192 

Generated on Tue Feb 2 17:46:04 2010 for RTAI API by  doxygen 1.4.7