⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91-fiq.patch

📁 linux内核不提供fiq的驱动的
💻 PATCH
字号:
diff -urN a/arch/arm/mach-at91rm9200/at91_fiq.c b/arch/arm/mach-at91rm9200/at91_fiq.c--- a/arch/arm/mach-at91rm9200/at91_fiq.c	1970-01-01 01:00:00.000000000 +0100+++ b/arch/arm/mach-at91rm9200/at91_fiq.c	2007-08-14 13:14:10.000000000 +0100@@ -0,0 +1,217 @@+/*+ * Copyright 2007  Andy Green <andy@warmcat.com>+ */++#include <linux/module.h>+#include <linux/kernel.h>+#include <asm/arch/at91rm9200.h>+#include <asm/arch/hardware.h>+#include <asm/arch/at91_pio.h>+#include <asm/cacheflush.h>++#include <asm/arch/at91rm9200_fiq_ipc_type.h>+++/*+ * HOW TO USE+ *+ * 1) Customize the struct in asm/archat91rm9200_fiq_ipc_type.h for your task+ *+ * 2) Customize the FIQ ISR routine at91rm9200_fiq_isr() below for your task+ *    at "Your C Code goes here"+ *+ * 3) Add the following in your kernel module so you+ *    can communicate with the FIQ ISR using at91rm9200_fiq_ipc+ *+ *    #include <asm/arch/at91rm9200_fiq_ipc_type.h>+ *    extern struct at91rm9200_fiq_ipc at91rm9200_fiq_ipc;+ *+ * 4) Have your kernel module call at91rm9200_fiq_init() on init and+ *    at91rm9200_fiq_exit() on exit -- prototypes are already in+ *    asm/arch/at91rm9200_fiq_ipc_type.h we included in step 3+ *+ * 5) Trigger a FIQ by giving a falling edge to PB28+ *+ *+ * Major Caveats for using FIQ+ * ---------------------------+ *+ * 1) it CANNOT touch any vmalloc()'d memory, only memory+ *    that was kmalloc()'d.  Static allocations in the monolithic kernel+ *    are kmalloc()'d so they are okay.  You can touch memory-mapped IO, but+ *    the pointer for it has to have been stored in kmalloc'd memory.  The+ *    reason for this is simple: every now and then Linux turns off interrupts+ *    and reorders the paging tables.  If a FIQ happens during this time, the+ *    virtual memory space can be partly or entirely disordered or missing.+ *+ * 2) Because vmalloc() is used when a module is inserted, THIS FIQ+ *    ISR HAS TO BE IN THE MONOLITHIC KERNEL, not a module.  But the way+ *    it is set up, you can all to enable and disable it from your module+ *    and intercommunicate with it through struct at91rm9200_fiq_ipc+ *    at91rm9200_fiq_ipc which you can define in+ *    asm/archat91rm9200_fiq_ipc_type.h.  The reason is the same as above, a+ *    FIQ could happen while even the ISR is not present in virtual memory+ *    space due to pagetables being changed at the time.+ *+ * 3) You can't call any Linux API code except simple macros+ *    - understand that FIQ can come in at any time, no matter what+ *      state of undress the kernel may privately be in, thinking it+ *      locked the door by turning off interrupts... FIQ is an+ *      unstoppable monster force (which is its value)+ *    - they are not vmalloc()'d memory safe+ *    - they might do crazy stuff like sleep: FIQ pisses fire and+ *      is not interested in 'sleep' that the weak seem to need+ *    - calling APIs from FIQ can re-enter un-renterable things+ *    - summary: you cannot interoperate with linux APIs directly in the FIQ ISR+ *+ * If you follow these rules, it is fantastic, an extremely powerful, solid,+ * genuine hard realtime feature.+ *+ */++#define AT91_PB28_FIQ           (1 << 28)       /* A: Fast Interrupt */++/* actual FIQ vector address where execution starts after FIQ */+#define AT91RM9200_FIQ_VECTOR 0xffff001c+/* more than enough to cover our jump instruction to the isr */+#define SIZEOF_FIQ_JUMP 8+/* more than enough to cover at91rm9200_fiq_isr() in 4K blocks */+#define SIZEOF_FIQ_ISR 0x2000++/* increase the size of the stack that is active during FIQ as needed */+static u8 u8aFiqStack[1024];++/* contains stuff FIQ ISR modifies and normal kernel code can see and use+ * this is defined in <asm/archat91rm9200_fiq_ipc_type.h>, you should customize+ * the definition in there and include the same definition in your kernel+ * module that wants to interoperate with your FIQ code.+ */+struct at91rm9200_fiq_ipc at91rm9200_fiq_ipc;+EXPORT_SYMBOL(at91rm9200_fiq_ipc);++/* the actual FIQ ISR */+static void __attribute__ ((naked))+at91rm9200_fiq_isr(void)+{+	/*+	*you can declare local vars here, take care to set the frame size+	* below accordingly if there are more than a few dozen bytes of them+	*/++	/* entry takes care to store registers we will be treading on here */+	asm __volatile__ (+		"mov     ip, sp ;"+		/* stash FIQ and r0-r8 normal regs */+		"stmdb	sp!, {r0-r8, r10-r12,  lr};"+		/* stash R9 separtely so we can have it first on exit */+		"stmdb	sp!, {r9};"+		/* !! THIS SETS THE FRAME, adjust to > sizeof locals */+		"sub     fp, ip, #256 ;"+		:+		:+		:"r9"+		);+/*+ * your C code goes here+ *+ * as an example, we bump a counter, you can rip that out when you+ * customize+ */+	at91rm9200_fiq_ipc.nCountFiqEvents++;+++	/* exit back to normal mode restoring everything */+	asm __volatile__ (+		/* pop R9 to contain &AT91_SYS->AIC_FVR */+		"ldmia	sp!, {r9};"+		/* read from it to acknowledge FIQ source */+		"ldr	r0, [r9];"+		/* return FIQ regs back to pristine state+		 * and get normal regs back+		 */+		"ldmia	sp!, {r0-r8, r10-r12, lr};"++		/* return */+		"subs	pc, lr, #4;"+	);+}+++/* this is copied into the hard FIQ vector during init */++static void __attribute__ ((naked))+at91rm9200_FIQ_Branch(void)+{+	asm __volatile__ (+		"mov pc, r8 ; "+	);+}+++/* call this from your kernel module to set up the FIQ ISR to service FIQs,+ * to enable the FIQ pin (PB28 on AT91RM9200) and to start accepting FIQs+ */+void+at91rm9200_fiq_init(void)+{+	struct pt_regs regs;+	register unsigned long tmp;+	+	printk("Enabling FIQ\n");++	/* set up PB28, the FIQ input pin */+	at91_sys_write(AT91_PIOB + PIO_PDR, AT91_PB28_FIQ);+	at91_sys_write(AT91_PIOB + PIO_ODR, AT91_PB28_FIQ);+	at91_sys_write(AT91_PIOB + PIO_ASR, AT91_PB28_FIQ);++	/* disable FIQ interrupt */+	at91_sys_write(AT91_AIC_IDCR, 1 << AT91_ID_FIQ);+	local_fiq_disable();+	+	/* prep the special FIQ mode regs */+	memset(&regs,0,sizeof(regs));+	regs.ARM_r8 = (long)at91rm9200_fiq_isr;+	regs.ARM_r9 = (long)AT91_VA_BASE_SYS+AT91_AIC_FVR;+	regs.ARM_sp = (long)u8aFiqStack + sizeof(u8aFiqStack) - 4;++	/* set up the special FIQ-mode-only registers from our regs */+	asm volatile (+		"mrs     %0, cpsr\n\+		msr     cpsr_c, %2      @ select FIQ mode\n\+		mov     r0, r0\n\+		ldmia   %1, {r8 - r14}\n\+		msr     cpsr_c, %0      @ return to SVC mode\n\+		mov     r0, r0\n"+		: "=&r" (tmp)+		: "r" (&regs.ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)+		: "r0"+	);++	/* copy our jump to the real ISR into the hard vector address */+	memcpy((void *)AT91RM9200_FIQ_VECTOR, at91rm9200_FIQ_Branch,+	    SIZEOF_FIQ_JUMP);+	+	/* flush this area */+	flush_icache_range(AT91RM9200_FIQ_VECTOR,+	    AT91RM9200_FIQ_VECTOR + SIZEOF_FIQ_JUMP);+	flush_icache_range((long)at91rm9200_fiq_isr,+	    (long)at91rm9200_fiq_isr + SIZEOF_FIQ_ISR);+	+	/* switch FIQ to edge triggered mode */+	at91_sys_write(AT91_AIC_SMR(0), 7 | AT91_AIC_SRCTYPE_FALLING);++	/* oho... set it going! */+	local_fiq_enable();+	at91_sys_write(AT91_AIC_IECR, 1 << AT91_ID_FIQ);+}+EXPORT_SYMBOL(at91rm9200_fiq_init);+++/* call this from your kernel module disable generation of FIQ actions */+void+at91rm9200_fiq_exit(void)+{+	at91_sys_write(AT91_AIC_IDCR, 1 << AT91_ID_FIQ);+	local_fiq_disable();+}+EXPORT_SYMBOL(at91rm9200_fiq_exit);diff -urN a/arch/arm/mach-at91rm9200/Makefile b/mach-at91rm9200/Makefile--- a/arch/arm/mach-at91rm9200/Makefile	2007-02-17 07:47:41.000000000 +0000+++ b/arch/arm/mach-at91rm9200/Makefile	2007-08-14 12:45:49.000000000 +0100@@ -11,7 +11,7 @@ obj-$(CONFIG_AT91_SLOW_CLOCK)	+= pm_slowclock.o  # CPU-specific support-obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o+obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o at91_fiq.o obj-$(CONFIG_ARCH_AT91SAM9260)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263.o at91sam926x_time.o at91sam9263_devices.odiff -urN a/include/asm-arm/arch-at91rm9200/at91rm9200_fiq_ipc_type.h b/include/asm-arm/arch-at91rm9200/at91rm9200_fiq_ipc_type.h--- a/include/asm-arm/arch-at91rm9200/at91rm9200_fiq_ipc_type.h	1970-01-01 01:00:00.000000000 +0100+++ b/include/asm-arm/arch-at91rm9200/at91rm9200_fiq_ipc_type.h	2007-08-14 10:07:50.000000000 +0100@@ -0,0 +1,26 @@+/*+ * this defines the struct which is used to communicate between the FIQ+ * world and the normal linux kernel world.  One of these structs is+ * statically defined for you in the monolithic kernel so the FIQ ISR code+ * can safely touch it any any time.+ *+ * You also want to include this file in your kernel module that wants to+ * communicate with your FIQ code.  Add any kinds of vars that are used by+ * the FIQ ISR and the module in here.+ *+ * To get you started there is just an int that is incremented every FIQ+ * you can remove this when you are ready to customize, but it is useful+ * for testing+ */++struct at91rm9200_fiq_ipc {+	int nCountFiqEvents;+};++/* inits and begins FIQ service */+void+at91rm9200_fiq_init(void);++/* stops FIQ events being seen any more */+void+at91rm9200_fiq_exit(void);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -