base/arch/i386/hal/rtc.c

Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2005 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 #ifdef INCLUDED_BY_HAL_C 00021 00022 #include <linux/mc146818rtc.h> 00023 00024 //#define TEST_RTC 00025 #define MIN_RTC_FREQ 2 00026 #define MAX_RTC_FREQ 8192 00027 #define RTC_FREQ MAX_RTC_FREQ 00028 00029 static void rt_broadcast_rtc_interrupt(void) 00030 { 00031 #ifdef CONFIG_SMP 00032 apic_wait_icr_idle(); 00033 apic_write_around(APIC_ICR, APIC_DM_FIXED | APIC_DEST_ALLINC | RTAI_APIC_TIMER_VECTOR | APIC_DEST_LOGICAL); 00034 #endif 00035 } 00036 00037 static void (*usr_rtc_handler)(void); 00038 00039 #if CONFIG_RTAI_DONT_DISPATCH_CORE_IRQS // && defined(CONFIG_RTAI_RTC_FREQ) && CONFIG_RTAI_RTC_FREQ 00040 00041 int _rtai_rtc_timer_handler(void) 00042 { 00043 unsigned long cpuid = rtai_cpuid(); 00044 rt_switch_to_real_time(cpuid); 00045 RTAI_SCHED_ISR_LOCK(); 00046 00047 rt_mask_and_ack_irq(RTC_IRQ); 00048 CMOS_READ(RTC_INTR_FLAGS); 00049 rt_enable_irq(RTC_IRQ); 00050 usr_rtc_handler(); 00051 00052 RTAI_SCHED_ISR_UNLOCK(); 00053 rt_switch_to_linux(cpuid); 00054 #if 1 //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) 00055 if (!test_bit(IPIPE_STALL_FLAG, &hal_root_domain->cpudata[cpuid].status)) { 00056 rtai_sti(); 00057 hal_fast_flush_pipeline(cpuid); 00058 #if defined(CONFIG_SMP) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,32) 00059 set_bit(IPIPE_STALL_FLAG, &hal_root_domain->cpudata[cpuid].status); 00060 #endif 00061 return 1; 00062 } 00063 #endif 00064 return 0; 00065 } 00066 00067 void rtai_rtc_timer_handler (void); 00068 __asm__ ( \ 00069 "\n" __ALIGN_STR"\n\t" \ 00070 SYMBOL_NAME_STR(rtai_rtc_timer_handler) ":\n\t" \ 00071 "pushl $-1\n\t" \ 00072 "cld\n\t" \ 00073 "pushl %es\n\t" \ 00074 "pushl %ds\n\t" \ 00075 "pushl %eax\n\t" \ 00076 "pushl %ebp\n\t" \ 00077 "pushl %edi\n\t" \ 00078 "pushl %esi\n\t" \ 00079 "pushl %edx\n\t" \ 00080 "pushl %ecx\n\t" \ 00081 "pushl %ebx\n\t" \ 00082 __LXRT_GET_DATASEG(ecx) \ 00083 "movl %ecx, %ds\n\t" \ 00084 "movl %ecx, %es\n\t" \ 00085 "call "SYMBOL_NAME_STR(_rtai_rtc_timer_handler)"\n\t" \ 00086 "testl %eax,%eax\n\t" \ 00087 "jnz ret_from_intr\n\t" \ 00088 "popl %ebx\n\t" \ 00089 "popl %ecx\n\t" \ 00090 "popl %edx\n\t" \ 00091 "popl %esi\n\t" \ 00092 "popl %edi\n\t" \ 00093 "popl %ebp\n\t" \ 00094 "popl %eax\n\t" \ 00095 "popl %ds\n\t" \ 00096 "popl %es\n\t" \ 00097 "addl $4,%esp\n\t" \ 00098 "iret"); 00099 00100 static struct desc_struct rtai_rtc_timer_sysvec; 00101 00102 #endif /* CONFIG_RTAI_DONT_DISPATCH_CORE_IRQS */ 00103 00104 /* 00105 * NOTE FOR USE IN RTAI_TRIOSS. 00106 * "rtc_freq" must be a power of 2 & (MIN_RTC_FREQ <= rtc_freq <= MAX_RTC_FREQ). 00107 * So the best thing to do is to load this module and your skin of choice 00108 * setting "rtc_freq" in this module and "rtc_freq" in the skin specific module 00109 * to the very same power of 2 that best fits your needs. 00110 */ 00111 00112 static void rtc_handler(int irq, int rtc_freq) 00113 { 00114 #ifdef TEST_RTC 00115 static int stp, cnt; 00116 if (++cnt == rtc_freq) { 00117 rt_printk("<> IRQ %d, %d: CNT %d <>\n", irq, ++stp, cnt); 00118 cnt = 0; 00119 } 00120 #endif 00121 CMOS_READ(RTC_INTR_FLAGS); 00122 rt_enable_irq(RTC_IRQ); 00123 if (usr_rtc_handler) { 00124 usr_rtc_handler(); 00125 } 00126 } 00127 00128 int fusion_timer_running; 00129 #ifdef RTAI_TRIOSS 00130 static void fusion_rtc_handler(void) 00131 { 00132 #ifdef CONFIG_X86_LOCAL_APIC 00133 #include <asm/apic.h> 00134 #include <mach_ipi.h> 00135 int cpuid; 00136 for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) { 00137 hal_pend_domain_uncond(RTAI_APIC_TIMER_VECTOR, fusion_domain, cpuid); 00138 } 00139 #ifdef CONFIG_SMP 00140 send_IPI_allbutself(RESCHEDULE_VECTOR); // any unharmful ipi suffices 00141 #endif 00142 #else 00143 hal_pend_domain_uncond(RTAI_TIMER_8254_IRQ, fusion_domain, rtai_cpuid()); 00144 #endif 00145 } 00146 EXPORT_SYMBOL(fusion_timer_running); 00147 #endif 00148 00149 void rt_request_rtc(long rtc_freq, void *handler) 00150 { 00151 int pwr2; 00152 00153 if (rtc_freq <= 0) { 00154 rtc_freq = RTC_FREQ; 00155 } 00156 if (rtc_freq > MAX_RTC_FREQ) { 00157 rtc_freq = MAX_RTC_FREQ; 00158 } else if (rtc_freq < MIN_RTC_FREQ) { 00159 rtc_freq = MIN_RTC_FREQ; 00160 } 00161 pwr2 = 1; 00162 if (rtc_freq > MIN_RTC_FREQ) { 00163 while (rtc_freq > (1 << pwr2)) { 00164 pwr2++; 00165 } 00166 if (rtc_freq <= ((3*(1 << (pwr2 - 1)) + 1)>>1)) { 00167 pwr2--; 00168 } 00169 } 00170 00171 rt_disable_irq(RTC_IRQ); 00172 rt_release_irq(RTC_IRQ); 00173 rtai_cli(); 00174 CMOS_WRITE(CMOS_READ(RTC_FREQ_SELECT), RTC_FREQ_SELECT); 00175 CMOS_WRITE(CMOS_READ(RTC_CONTROL), RTC_CONTROL); 00176 CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - pwr2), RTC_FREQ_SELECT); 00177 CMOS_WRITE((CMOS_READ(RTC_CONTROL) & 0x8F) | RTC_PIE, RTC_CONTROL); 00178 rtai_sti(); 00179 #ifdef RTAI_TRIOSS 00180 usr_rtc_handler = fusion_rtc_handler; 00181 #else 00182 usr_rtc_handler = handler ? handler : rt_broadcast_rtc_interrupt; 00183 #endif 00184 SET_FUSION_TIMER_RUNNING(); 00185 #ifdef TEST_RTC 00186 rt_printk("<%s>\n", fusion_timer_running ? "FUSION TIMER RUNNING" : ""); 00187 #endif 00188 rt_request_irq(RTC_IRQ, (void *)rtc_handler, (void *)rtc_freq, 0); 00189 SET_INTR_GATE(ext_irq_vector(RTC_IRQ), rtai_rtc_timer_handler, rtai_rtc_timer_sysvec); 00190 rt_enable_irq(RTC_IRQ); 00191 CMOS_READ(RTC_INTR_FLAGS); 00192 return; 00193 } 00194 00195 void rt_release_rtc(void) 00196 { 00197 rt_disable_irq(RTC_IRQ); 00198 usr_rtc_handler = NULL; 00199 CLEAR_FUSION_TIMER_RUNNING(); 00200 RESET_INTR_GATE(ext_irq_vector(RTC_IRQ), rtai_rtc_timer_sysvec); 00201 rt_release_irq(RTC_IRQ); 00202 rtai_cli(); 00203 CMOS_WRITE(CMOS_READ(RTC_FREQ_SELECT), RTC_FREQ_SELECT); 00204 CMOS_WRITE(CMOS_READ(RTC_CONTROL), RTC_CONTROL); 00205 rtai_sti(); 00206 return; 00207 } 00208 00209 EXPORT_SYMBOL(rt_request_rtc); 00210 EXPORT_SYMBOL(rt_release_rtc); 00211 00212 #endif /* INCLUDED_BY_HAL_C */

Generated on Thu Nov 20 11:49:47 2008 for RTAI API by doxygen 1.3.8