[alsa-cvslog] alsa-driver: pc-speaker driver update for 2.6.18
Brought to you by:
perex
From: Takashi I. <ti...@su...> - 2006-10-04 19:08:21
|
changeset: 3149:d0a08ac235a53272ffa34158bed851fc7828f484 tag: tip user: tiwai date: Wed Oct 04 21:09:44 2006 +0200 files: utils/patches/pcsp-kernel-2.6.18-01.diff description: pc-speaker driver update for 2.6.18 pc-speaker hook patch for 2.6.18 Signed-off-by: Stas Sergeev <st...@ak...> diff -r 518881e5990978672090d12008d37686473b0560 -r d0a08ac235a53272ffa34= 158bed851fc7828f484 utils/patches/pcsp-kernel-2.6.18-01.diff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/patches/pcsp-kernel-2.6.18-01.diff Wed Oct 04 21:09:44 2006 += 0200 @@ -0,0 +1,591 @@ +diff -urN linux-2.6.18/arch/i386/Kconfig linux-2.6.18-pcsp-kern/arch/i38= 6/Kconfig +--- linux-2.6.18/arch/i386/Kconfig 2006-08-29 14:15:46.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/arch/i386/Kconfig 2006-09-27 15:47:34.0000000= 00 +0400 +@@ -1187,3 +1187,8 @@ + config KTIME_SCALAR + bool + default y ++ ++config HAVE_PCSP_HOOK ++ bool ++ depends on X86_PC ++ default y +diff -urN linux-2.6.18/arch/i386/kernel/i8253.c linux-2.6.18-pcsp-kern/a= rch/i386/kernel/i8253.c +--- linux-2.6.18/arch/i386/kernel/i8253.c 2006-08-29 14:15:04.000000000 = +0400 ++++ linux-2.6.18-pcsp-kern/arch/i386/kernel/i8253.c 2006-09-27 16:07:49.= 000000000 +0400 +@@ -63,6 +63,7 @@ + outb_p(0x00, PIT_MODE); /* latch the count ASAP */ + count =3D inb_p(PIT_CH0); /* read the latched count */ + count |=3D inb_p(PIT_CH0) << 8; ++ count +=3D pit_counter0_offset; +=20 + /* VIA686a test code... reset the latch if count > max + 1 */ + if (count > LATCH) { +diff -urN linux-2.6.18/arch/i386/kernel/time.c linux-2.6.18-pcsp-kern/ar= ch/i386/kernel/time.c +--- linux-2.6.18/arch/i386/kernel/time.c 2006-08-29 14:15:37.000000000 += 0400 ++++ linux-2.6.18-pcsp-kern/arch/i386/kernel/time.c 2006-09-27 15:52:44.0= 00000000 +0400 +@@ -73,6 +73,9 @@ +=20 + #include "do_timer.h" +=20 ++volatile int pit_counter0_offset =3D 0; ++EXPORT_SYMBOL(pit_counter0_offset); ++ + unsigned int cpu_khz; /* Detected as we calibrate the TSC */ + EXPORT_SYMBOL(cpu_khz); +=20 +@@ -143,6 +146,26 @@ + EXPORT_SYMBOL(profile_pc); + #endif +=20 ++static int do_process_time(struct pt_regs *regs) ++{ ++#ifndef CONFIG_SMP ++ update_process_times(user_mode(regs)); ++#endif ++/* ++ * In the SMP case we use the local APIC timer interrupt to do the ++ * profiling, except when we simulate SMP mode on a uniprocessor ++ * system, in that case we have to call the local interrupt handler. ++ */ ++#ifndef CONFIG_X86_LOCAL_APIC ++ profile_tick(CPU_PROFILING, regs); ++#else ++ if (!using_apic_timer) ++ smp_local_timer_interrupt(regs); ++#endif ++ return 0; ++} ++ ++ + /* + * This is the same as the above, except we _also_ save the current + * Time Stamp Counter value at the time of the timer interrupt, so that +@@ -329,6 +352,9 @@ +=20 + device_initcall(time_init_device); +=20 ++static struct timer_hook hook1 =3D { .hook_fn =3D do_timer, .run_always= =3D 0 }; ++static struct timer_hook hook2 =3D { .hook_fn =3D do_process_time, .run= _always =3D 0 }; ++ + #ifdef CONFIG_HPET_TIMER + extern void (*late_time_init)(void); + /* Duplicate of time_init() below, with hpet_enable part added */ +@@ -343,7 +369,10 @@ + printk("Using HPET for base-timer\n"); + } +=20 ++ /* register timer hooks in reverse order */ + time_init_hook(); ++ setup_timer_hook(&hook2); ++ setup_timer_hook(&hook1); + } + #endif +=20 +@@ -365,4 +394,6 @@ + -xtime.tv_sec, -xtime.tv_nsec); +=20 + time_init_hook(); ++ setup_timer_hook(&hook2); ++ setup_timer_hook(&hook1); + } +diff -urN linux-2.6.18/arch/i386/mach-visws/setup.c linux-2.6.18-pcsp-ke= rn/arch/i386/mach-visws/setup.c +--- linux-2.6.18/arch/i386/mach-visws/setup.c 2006-08-29 14:15:04.000000= 000 +0400 ++++ linux-2.6.18-pcsp-kern/arch/i386/mach-visws/setup.c 2006-09-27 15:47= :51.000000000 +0400 +@@ -119,6 +119,15 @@ + .name =3D "timer", + }; +=20 ++static int co_clear_timerint(struct pt_regs *regs) ++{ ++ /* Clear the interrupt */ ++ co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR)= ; ++ return 0; ++} ++ ++ ++static struct timer_hook hook =3D { .hook_fn =3D co_clear_timerint, .ru= n_always =3D 1 }; + void __init time_init_hook(void) + { + printk(KERN_INFO "Starting Cobalt Timer system clock\n"); +@@ -132,6 +141,8 @@ + /* Enable (unmask) the timer interrupt */ + co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK= ); +=20 ++ setup_timer_hook(&hook); ++ + /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ + setup_irq(0, &irq0); + } +diff -urN linux-2.6.18/arch/i386/mach-voyager/setup.c linux-2.6.18-pcsp-= kern/arch/i386/mach-voyager/setup.c +--- linux-2.6.18/arch/i386/mach-voyager/setup.c 2006-08-29 14:15:04.0000= 00000 +0400 ++++ linux-2.6.18-pcsp-kern/arch/i386/mach-voyager/setup.c 2006-09-27 15:= 58:33.000000000 +0400 +@@ -41,9 +41,11 @@ + } +=20 + static struct irqaction irq0 =3D { timer_interrupt, IRQF_DISABLED, CPU= _MASK_NONE, "timer", NULL, NULL}; ++static struct timer_hook hook =3D { .hook_fn =3D voyager_timer_interrup= t, .run_always =3D 1 }; +=20 + void __init time_init_hook(void) + { ++ setup_timer_hook(&hook); + setup_irq(0, &irq0); + } +=20 +diff -urN linux-2.6.18/arch/i386/mach-voyager/voyager_basic.c linux-2.6.= 18-pcsp-kern/arch/i386/mach-voyager/voyager_basic.c +--- linux-2.6.18/arch/i386/mach-voyager/voyager_basic.c 2006-08-29 14:15= :04.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/arch/i386/mach-voyager/voyager_basic.c 2006-0= 9-27 15:47:51.000000000 +0400 +@@ -165,8 +165,7 @@ + /* voyager specific handling code for timer interrupts. Used to hand + * off the timer tick to the SMP code, since the VIC doesn't have an + * internal timer (The QIC does, but that's another story). */ +-void +-voyager_timer_interrupt(struct pt_regs *regs) ++int voyager_timer_interrupt(struct pt_regs *regs) + { + if((jiffies & 0x3ff) =3D=3D 0) { +=20 +@@ -204,6 +203,7 @@ + #ifdef CONFIG_SMP + smp_vic_timer_interrupt(regs); + #endif ++ return 0; + } +=20 + void +diff -urN linux-2.6.18/CREDITS linux-2.6.18-pcsp-kern/CREDITS +--- linux-2.6.18/CREDITS 2006-08-29 14:15:46.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/CREDITS 2006-09-27 15:47:51.000000000 +0400 +@@ -395,6 +395,8 @@ + N: Erik Inge Bols=F8 + E: kn...@mo... + D: Misc kernel hacks ++D: Updated PC speaker driver for 2.3 ++S: Norway +=20 + N: Andreas E. Bombe + E: and...@mu... +@@ -3027,6 +3029,12 @@ + S: Sunnyvale, California 94088-4132 + S: USA +=20 ++N: Stas Sergeev ++E: st...@us... ++D: PC-Speaker driver ++D: misc fixes ++S: Russia ++ + N: Simon Shapiro + E: sh...@i-... + W: http://www.-i-Connect.Net/~shimon +diff -urN linux-2.6.18/drivers/input/gameport/gameport.c linux-2.6.18-pc= sp-kern/drivers/input/gameport/gameport.c +--- linux-2.6.18/drivers/input/gameport/gameport.c 2006-08-29 14:15:42.0= 00000000 +0400 ++++ linux-2.6.18-pcsp-kern/drivers/input/gameport/gameport.c 2006-09-27 = 15:47:51.000000000 +0400 +@@ -75,6 +75,7 @@ + outb_p(0x00, 0x43); + count =3D inb_p(0x40); + count |=3D inb_p(0x40) << 8; ++ count +=3D pit_counter0_offset; + spin_unlock_irqrestore(&i8253_lock, flags); +=20 + return count; +diff -urN linux-2.6.18/drivers/input/joystick/analog.c linux-2.6.18-pcsp= -kern/drivers/input/joystick/analog.c +--- linux-2.6.18/drivers/input/joystick/analog.c 2006-08-29 14:15:07.000= 000000 +0400 ++++ linux-2.6.18-pcsp-kern/drivers/input/joystick/analog.c 2006-09-27 15= :47:51.000000000 +0400 +@@ -155,6 +155,7 @@ + outb_p(0x00, 0x43); + count =3D inb_p(0x40); + count |=3D inb_p(0x40) << 8; ++ count +=3D pit_counter0_offset; + spin_unlock_irqrestore(&i8253_lock, flags); +=20 + return count; +diff -urN linux-2.6.18/drivers/input/misc/Kconfig linux-2.6.18-pcsp-kern= /drivers/input/misc/Kconfig +--- linux-2.6.18/drivers/input/misc/Kconfig 2006-08-29 14:15:07.00000000= 0 +0400 ++++ linux-2.6.18-pcsp-kern/drivers/input/misc/Kconfig 2006-09-27 15:47:5= 1.000000000 +0400 +@@ -14,7 +14,7 @@ +=20 + config INPUT_PCSPKR + tristate "PC Speaker support" +- depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES ++ depends on (ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIE= S) && !HAVE_PCSP_HOOK + help + Say Y here if you want the standard PC Speaker to be used for + bells and whistles. +diff -urN linux-2.6.18/drivers/oprofile/timer_int.c linux-2.6.18-pcsp-ke= rn/drivers/oprofile/timer_int.c +--- linux-2.6.18/drivers/oprofile/timer_int.c 2006-08-29 14:10:49.000000= 000 +0400 ++++ linux-2.6.18-pcsp-kern/drivers/oprofile/timer_int.c 2006-09-27 15:47= :51.000000000 +0400 +@@ -12,11 +12,14 @@ + #include <linux/smp.h> + #include <linux/oprofile.h> + #include <linux/profile.h> ++#include <linux/timer.h> + #include <linux/init.h> + #include <asm/ptrace.h> +=20 + #include "oprof.h" +=20 ++static void *hook_ptr; ++ + static int timer_notify(struct pt_regs *regs) + { + oprofile_add_sample(regs, 0); +@@ -25,13 +28,14 @@ +=20 + static int timer_start(void) + { +- return register_timer_hook(timer_notify); ++ hook_ptr =3D register_timer_hook(timer_notify); ++ return !hook_ptr; + } +=20 +=20 + static void timer_stop(void) + { +- unregister_timer_hook(timer_notify); ++ unregister_timer_hook(hook_ptr); + } +=20 +=20 +diff -urN linux-2.6.18/include/asm-i386/mach-default/do_timer.h linux-2.= 6.18-pcsp-kern/include/asm-i386/mach-default/do_timer.h +--- linux-2.6.18/include/asm-i386/mach-default/do_timer.h 2006-08-29 14:= 10:20.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/include/asm-i386/mach-default/do_timer.h 2006= -09-27 15:47:51.000000000 +0400 +@@ -3,37 +3,6 @@ + #include <asm/apic.h> + #include <asm/i8259.h> +=20 +-/** +- * do_timer_interrupt_hook - hook into timer tick +- * @regs: standard registers from interrupt +- * +- * Description: +- * This hook is called immediately after the timer interrupt is ack'd. +- * It's primary purpose is to allow architectures that don't possess +- * individual per CPU clocks (like the CPU APICs supply) to broadcast t= he +- * timer interrupt as a means of triggering reschedules etc. +- **/ +- +-static inline void do_timer_interrupt_hook(struct pt_regs *regs) +-{ +- do_timer(regs); +-#ifndef CONFIG_SMP +- update_process_times(user_mode_vm(regs)); +-#endif +-/* +- * In the SMP case we use the local APIC timer interrupt to do the +- * profiling, except when we simulate SMP mode on a uniprocessor +- * system, in that case we have to call the local interrupt handler. +- */ +-#ifndef CONFIG_X86_LOCAL_APIC +- profile_tick(CPU_PROFILING, regs); +-#else +- if (!using_apic_timer) +- smp_local_timer_interrupt(regs); +-#endif +-} +- +- + /* you can safely undefine this if you don't have the Neptune chipset *= / +=20 + #define BUGGY_NEPTUN_TIMER +diff -urN linux-2.6.18/include/asm-i386/mach-visws/do_timer.h linux-2.6.= 18-pcsp-kern/include/asm-i386/mach-visws/do_timer.h +--- linux-2.6.18/include/asm-i386/mach-visws/do_timer.h 2006-08-29 14:10= :20.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/include/asm-i386/mach-visws/do_timer.h 2006-0= 9-27 15:47:51.000000000 +0400 +@@ -4,28 +4,6 @@ + #include <asm/i8259.h> + #include "cobalt.h" +=20 +-static inline void do_timer_interrupt_hook(struct pt_regs *regs) +-{ +- /* Clear the interrupt */ +- co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR)= ; +- +- do_timer(regs); +-#ifndef CONFIG_SMP +- update_process_times(user_mode_vm(regs)); +-#endif +-/* +- * In the SMP case we use the local APIC timer interrupt to do the +- * profiling, except when we simulate SMP mode on a uniprocessor +- * system, in that case we have to call the local interrupt handler. +- */ +-#ifndef CONFIG_X86_LOCAL_APIC +- profile_tick(CPU_PROFILING, regs); +-#else +- if (!using_apic_timer) +- smp_local_timer_interrupt(regs); +-#endif +-} +- + static inline int do_timer_overflow(int count) + { + int i; +diff -urN linux-2.6.18/include/asm-i386/mach-voyager/do_timer.h linux-2.= 6.18-pcsp-kern/include/asm-i386/mach-voyager/do_timer.h +--- linux-2.6.18/include/asm-i386/mach-voyager/do_timer.h 2006-08-29 14:= 10:20.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/include/asm-i386/mach-voyager/do_timer.h 2006= -09-27 15:47:51.000000000 +0400 +@@ -1,16 +1,6 @@ + /* defines for inline arch setup functions */ + #include <asm/voyager.h> +=20 +-static inline void do_timer_interrupt_hook(struct pt_regs *regs) +-{ +- do_timer(regs); +-#ifndef CONFIG_SMP +- update_process_times(user_mode_vm(regs)); +-#endif +- +- voyager_timer_interrupt(regs); +-} +- + static inline int do_timer_overflow(int count) + { + /* can't read the ISR, just assume 1 tick +diff -urN linux-2.6.18/include/asm-i386/timex.h linux-2.6.18-pcsp-kern/i= nclude/asm-i386/timex.h +--- linux-2.6.18/include/asm-i386/timex.h 2006-08-29 14:15:18.000000000 = +0400 ++++ linux-2.6.18-pcsp-kern/include/asm-i386/timex.h 2006-09-27 15:47:51.= 000000000 +0400 +@@ -19,4 +19,6 @@ + extern int read_current_timer(unsigned long *timer_value); + #define ARCH_HAS_READ_CURRENT_TIMER 1 +=20 ++extern volatile int pit_counter0_offset; ++ + #endif +diff -urN linux-2.6.18/include/asm-i386/voyager.h linux-2.6.18-pcsp-kern= /include/asm-i386/voyager.h +--- linux-2.6.18/include/asm-i386/voyager.h 2006-08-29 14:10:20.00000000= 0 +0400 ++++ linux-2.6.18-pcsp-kern/include/asm-i386/voyager.h 2006-09-27 15:47:5= 1.000000000 +0400 +@@ -505,7 +505,7 @@ + extern void voyager_smp_intr_init(void); + extern __u8 voyager_extended_cmos_read(__u16 cmos_address); + extern void voyager_smp_dump(void); +-extern void voyager_timer_interrupt(struct pt_regs *regs); ++extern int voyager_timer_interrupt(struct pt_regs *regs); + extern void smp_local_timer_interrupt(struct pt_regs * regs); + extern void voyager_power_off(void); + extern void smp_voyager_power_off(void *dummy); +diff -urN linux-2.6.18/include/linux/profile.h linux-2.6.18-pcsp-kern/in= clude/linux/profile.h +--- linux-2.6.18/include/linux/profile.h 2006-08-29 14:15:22.000000000 += 0400 ++++ linux-2.6.18-pcsp-kern/include/linux/profile.h 2006-09-27 15:47:51.0= 00000000 +0400 +@@ -52,12 +52,6 @@ + int profile_event_register(enum profile_type, struct notifier_block * n= ); + int profile_event_unregister(enum profile_type, struct notifier_block *= n); +=20 +-int register_timer_hook(int (*hook)(struct pt_regs *)); +-void unregister_timer_hook(int (*hook)(struct pt_regs *)); +- +-/* Timer based profiling hook */ +-extern int (*timer_hook)(struct pt_regs *); +- + struct pt_regs; +=20 + #else +@@ -86,16 +80,6 @@ + #define profile_handoff_task(a) (0) + #define profile_munmap(a) do { } while (0) +=20 +-static inline int register_timer_hook(int (*hook)(struct pt_regs *)) +-{ +- return -ENOSYS; +-} +- +-static inline void unregister_timer_hook(int (*hook)(struct pt_regs *)) +-{ +- return; +-} +- + #endif /* CONFIG_PROFILING */ +=20 + #endif /* __KERNEL__ */ +diff -urN linux-2.6.18/include/linux/sched.h linux-2.6.18-pcsp-kern/incl= ude/linux/sched.h +--- linux-2.6.18/include/linux/sched.h 2006-09-12 14:23:36.000000000 +04= 00 ++++ linux-2.6.18-pcsp-kern/include/linux/sched.h 2006-09-27 15:47:51.000= 000000 +0400 +@@ -1179,7 +1179,7 @@ +=20 + #include <asm/current.h> +=20 +-extern void do_timer(struct pt_regs *); ++extern int do_timer(struct pt_regs *); +=20 + extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned in= t state)); + extern int FASTCALL(wake_up_process(struct task_struct * tsk)); +diff -urN linux-2.6.18/include/linux/timer.h linux-2.6.18-pcsp-kern/incl= ude/linux/timer.h +--- linux-2.6.18/include/linux/timer.h 2006-08-29 14:15:22.000000000 +04= 00 ++++ linux-2.6.18-pcsp-kern/include/linux/timer.h 2006-09-27 15:47:51.000= 000000 +0400 +@@ -98,4 +98,17 @@ + struct hrtimer; + extern int it_real_fn(struct hrtimer *); +=20 ++struct timer_hook { ++ int (*hook_fn)(struct pt_regs *regs); ++ int run_always; ++ struct list_head list; ++}; ++extern void do_timer_interrupt_hook(struct pt_regs *regs); ++extern void setup_timer_hook(struct timer_hook *hook); ++extern void remove_timer_hook(struct timer_hook *hook); ++extern void *register_timer_hook(int (*hook)(struct pt_regs *)); ++extern void unregister_timer_hook(void *hook_ptr); ++extern int grab_timer_hook(void *hook_ptr); ++extern void ungrab_timer_hook(void *hook_ptr); ++ + #endif +diff -urN linux-2.6.18/kernel/profile.c linux-2.6.18-pcsp-kern/kernel/pr= ofile.c +--- linux-2.6.18/kernel/profile.c 2006-08-29 14:15:23.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/kernel/profile.c 2006-09-27 15:47:51.00000000= 0 +0400 +@@ -34,9 +34,6 @@ + #define NR_PROFILE_HIT (PAGE_SIZE/sizeof(struct profile_hit)) + #define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ) +=20 +-/* Oprofile timer tick hook */ +-int (*timer_hook)(struct pt_regs *) __read_mostly; +- + static atomic_t *prof_buffer; + static unsigned long prof_len, prof_shift; + static int prof_on __read_mostly; +@@ -154,24 +151,6 @@ + return err; + } +=20 +-int register_timer_hook(int (*hook)(struct pt_regs *)) +-{ +- if (timer_hook) +- return -EBUSY; +- timer_hook =3D hook; +- return 0; +-} +- +-void unregister_timer_hook(int (*hook)(struct pt_regs *)) +-{ +- WARN_ON(hook !=3D timer_hook); +- timer_hook =3D NULL; +- /* make sure all CPUs see the NULL hook */ +- synchronize_sched(); /* Allow ongoing interrupts to complete. */ +-} +- +-EXPORT_SYMBOL_GPL(register_timer_hook); +-EXPORT_SYMBOL_GPL(unregister_timer_hook); + EXPORT_SYMBOL_GPL(task_handoff_register); + EXPORT_SYMBOL_GPL(task_handoff_unregister); +=20 +@@ -364,8 +343,6 @@ +=20 + void profile_tick(int type, struct pt_regs *regs) + { +- if (type =3D=3D CPU_PROFILING && timer_hook) +- timer_hook(regs); + if (!user_mode(regs) && cpu_isset(smp_processor_id(), prof_cpu_mask)) + profile_hit(type, (void *)profile_pc(regs)); + } +diff -urN linux-2.6.18/kernel/timer.c linux-2.6.18-pcsp-kern/kernel/time= r.c +--- linux-2.6.18/kernel/timer.c 2006-08-29 14:15:47.000000000 +0400 ++++ linux-2.6.18-pcsp-kern/kernel/timer.c 2006-09-27 15:47:51.000000000 = +0400 +@@ -80,6 +80,13 @@ + tvec_t tv5; + } ____cacheline_aligned_in_smp; +=20 ++struct timer_hook_list { ++ struct list_head head; ++ struct timer_hook *grab; ++ spinlock_t lock; ++}; ++static struct timer_hook_list timer_hook_list; ++ + typedef struct tvec_t_base_s tvec_base_t; +=20 + tvec_base_t boot_tvec_bases; +@@ -1281,12 +1288,13 @@ + * jiffies is defined in the linker script... + */ +=20 +-void do_timer(struct pt_regs *regs) ++int do_timer(struct pt_regs *regs) + { + jiffies_64++; + /* prevent loading jiffies before storing new jiffies_64 value. */ + barrier(); + update_times(); ++ return 0; + } +=20 + #ifdef __ARCH_WANT_SYS_ALARM +@@ -1688,6 +1696,10 @@ +=20 + void __init init_timers(void) + { ++ INIT_LIST_HEAD(&timer_hook_list.head); ++ spin_lock_init(&timer_hook_list.lock); ++ timer_hook_list.grab =3D NULL; ++ + timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE, + (void *)(long)smp_processor_id()); + register_cpu_notifier(&timers_nb); +@@ -1910,3 +1922,70 @@ + } +=20 + EXPORT_SYMBOL(msleep_interruptible); ++ ++ ++ ++void do_timer_interrupt_hook(struct pt_regs *regs) ++{ ++ struct timer_hook *ptr; ++ int done =3D 0; ++ if (unlikely(timer_hook_list.grab)) ++ done =3D timer_hook_list.grab->hook_fn(regs); ++ /* called within IRQ context, rcu_read_lock not needed? */ ++ list_for_each_entry_rcu(ptr, &timer_hook_list.head, list) { ++ if (!done || ptr->run_always) ++ ptr->hook_fn(regs); ++ } ++} ++ ++void setup_timer_hook(struct timer_hook *hook) ++{ ++ spin_lock(&timer_hook_list.lock); ++ list_add_rcu(&hook->list, &timer_hook_list.head); ++ spin_unlock(&timer_hook_list.lock); ++} ++ ++void remove_timer_hook(struct timer_hook *hook) ++{ ++ spin_lock(&timer_hook_list.lock); ++ list_del_rcu(&hook->list); ++ spin_unlock(&timer_hook_list.lock); ++} ++ ++void *register_timer_hook(int (*func)(struct pt_regs *)) ++{ ++ struct timer_hook *ptr; ++ ptr =3D kmalloc(sizeof(struct timer_hook), GFP_ATOMIC); ++ ptr->hook_fn =3D func; ++ ptr->run_always =3D 0; ++ setup_timer_hook(ptr); ++ return ptr; ++} ++ ++void unregister_timer_hook(void *hook_ptr) ++{ ++ struct timer_hook *ptr =3D (struct timer_hook *)hook_ptr; ++ remove_timer_hook(ptr); ++ kfree(ptr); ++} ++ ++int grab_timer_hook(void *hook_ptr) ++{ ++ if (timer_hook_list.grab) ++ return -EBUSY; ++ timer_hook_list.grab =3D (struct timer_hook *)hook_ptr; ++ return 0; ++} ++ ++void ungrab_timer_hook(void *hook_ptr) ++{ ++ WARN_ON(timer_hook_list.grab !=3D (struct timer_hook *)hook_ptr); ++ timer_hook_list.grab =3D NULL; ++} ++ ++EXPORT_SYMBOL_GPL(setup_timer_hook); ++EXPORT_SYMBOL_GPL(remove_timer_hook); ++EXPORT_SYMBOL_GPL(register_timer_hook); ++EXPORT_SYMBOL_GPL(unregister_timer_hook); ++EXPORT_SYMBOL_GPL(grab_timer_hook); ++EXPORT_SYMBOL_GPL(ungrab_timer_hook); |