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

📄 irq.c

📁 linux-2.6.15.6
💻 C
字号:
/*  * Copyright (C) 2000 David J. Mckay (david.mckay@st.com) * * May be copied or modified under the terms of the GNU General Public * License.  See linux/COPYING for more information.                             * * Looks after interrupts on the overdrive board. * * Bases on the IPR irq system */#include <linux/config.h>#include <linux/init.h>#include <linux/irq.h>#include <asm/system.h>#include <asm/io.h>#include <asm/overdrive/overdrive.h>struct od_data {	int overdrive_irq;	int irq_mask;};#define NUM_EXTERNAL_IRQS 16#define EXTERNAL_IRQ_NOT_IN_USE (-1)#define EXTERNAL_IRQ_NOT_ASSIGNED (-1)/* * This table is used to determine what to program into the FPGA's CT register * for the specified Linux IRQ. * * The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0)) * but is one greater than that because the because the FPGA treats 0 * as disabled, a value of 1 asserts PCI_Int0, and so on. * * The overdrive_irq specifies which of the eight interrupt sources generates * that interrupt, and but is multiplied by four to give the bit offset into * the CT register. * * The seven interrupts levels (SH4 IRL's) we have available here is hardwired * by the EPLD. The assignments here of which PCI interrupt generates each * level is arbitary. */static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = {	/*    overdrive_irq       , irq_mask */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 0 */	{EXTERNAL_IRQ_NOT_ASSIGNED, 7},	/* 1 */	{EXTERNAL_IRQ_NOT_ASSIGNED, 6},	/* 2 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 3 */	{EXTERNAL_IRQ_NOT_ASSIGNED, 5},	/* 4 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 5 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 6 */	{EXTERNAL_IRQ_NOT_ASSIGNED, 4},	/* 7 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 8 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 9 */	{EXTERNAL_IRQ_NOT_ASSIGNED, 3},	/* 10 */	{EXTERNAL_IRQ_NOT_ASSIGNED, 2},	/* 11 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 12 */	{EXTERNAL_IRQ_NOT_ASSIGNED, 1},	/* 13 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE},	/* 14 */	{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}	/* 15 */};static void set_od_data(int overdrive_irq, int irq){	if (irq >= NUM_EXTERNAL_IRQS || irq < 0)		return;	od_data_table[irq].overdrive_irq = overdrive_irq << 2;}static void enable_od_irq(unsigned int irq);void disable_od_irq(unsigned int irq);/* shutdown is same as "disable" */#define shutdown_od_irq disable_od_irqstatic void mask_and_ack_od(unsigned int);static void end_od_irq(unsigned int irq);static unsigned int startup_od_irq(unsigned int irq){	enable_od_irq(irq);	return 0;		/* never anything pending */}static struct hw_interrupt_type od_irq_type = {	.typename = "Overdrive-IRQ",	.startup = startup_od_irq,	.shutdown = shutdown_od_irq,	.enable = enable_od_irq,	.disable = disable_od_irq,	.ack = mask_and_ack_od,	.end = end_od_irq};static void disable_od_irq(unsigned int irq){	unsigned val, flags;	int overdrive_irq;	unsigned mask;	/* Not a valid interrupt */	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)		return;        /* Is is necessary to use a cli here? Would a spinlock not be          * mroe efficient?         */	local_irq_save(flags);	overdrive_irq = od_data_table[irq].overdrive_irq;	if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {		mask = ~(0x7 << overdrive_irq);		val = ctrl_inl(OVERDRIVE_INT_CT);		val &= mask;		ctrl_outl(val, OVERDRIVE_INT_CT);	}	local_irq_restore(flags);}static void enable_od_irq(unsigned int irq){	unsigned val, flags;	int overdrive_irq;	unsigned mask;	/* Not a valid interrupt */	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)		return;	/* Set priority in OD back to original value */	local_irq_save(flags);	/* This one is not in use currently */	overdrive_irq = od_data_table[irq].overdrive_irq;	if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {		val = ctrl_inl(OVERDRIVE_INT_CT);		mask = ~(0x7 << overdrive_irq);		val &= mask;		mask = od_data_table[irq].irq_mask << overdrive_irq;		val |= mask;		ctrl_outl(val, OVERDRIVE_INT_CT);	}	local_irq_restore(flags);}/* this functions sets the desired irq handler to be an overdrive type */static void __init make_od_irq(unsigned int irq){	disable_irq_nosync(irq);	irq_desc[irq].handler = &od_irq_type;	disable_od_irq(irq);}static void mask_and_ack_od(unsigned int irq){	disable_od_irq(irq);}static void end_od_irq(unsigned int irq){	enable_od_irq(irq);}void __init init_overdrive_irq(void){	int i;	/* Disable all interrupts */	ctrl_outl(0, OVERDRIVE_INT_CT);	/* Update interrupt pin mode to use encoded interrupts */	i = ctrl_inw(INTC_ICR);	i &= ~INTC_ICR_IRLM;	ctrl_outw(i, INTC_ICR);	for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {		if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) {			make_od_irq(i);		} else if (i != 15) {	// Cannot use imask on level 15			make_imask_irq(i);		}	}	/* Set up the interrupts */	set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1);	set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2);	set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ);}

⌨️ 快捷键说明

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