arm linux 断电影响,armlinux中断分析

------------------------------------本文系本站原创,欢迎转载!转载请注明出处:http://sjj0412.cublog.cn/

------------------------------------

今天讲一下s3c2410等arm开发板下linux中断相关的操作。

首先当然是进入start_kernel了,这里有中断初始化的函数

asmlinkage void

__init start_kernel(void)

{

………….

………….

init_IRQ();

……………..

……………

}

void __init init_IRQ(void)

{

struct

irqdesc *desc;

extern

void init_dma(void);

int

irq;

#ifdef CONFIG_SMP

bad_irq_desc.affinity

= CPU_MASK_ALL;

bad_irq_desc.cpu

= smp_processor_id();

#endif

for

(irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {

*desc

= bad_irq_desc;

INIT_LIST_HEAD(&desc->pend);

}

//前面注册了哑铃中断

init_arch_irq();//注册具体开发板的中断。

init_dma();

}

init_arch_irq()这个函数又在哪里呢,它就是在这里

MACHINE_START(QQ2440, "QQ2440")

.phys_ram= S3C2410_SDRAM_PA,

.phys_io= S3C2410_PA_UART,

.io_pg_offst= (((u32)S3C24XX_VA_UART) >> 18) &

0xfffc,

.boot_params= S3C2410_SDRAM_PA + 0x100,

.init_irq=

sbc2440_init_irq,

.map_io= sbc2440_map_io,

.init_machine= sbc2440_init,

.timer= &s3c24xx_timer,

MACHINE_END

因此就调用具体开发板的中断初始函数。

sbc2440_init_irq然后调用s3c24xx_init_irq,我们知道中断在Linux以全局变量struct irqdesc

irq_desc[NR_IRQS]管理;

struct irqdesc {

irq_handler_thandle;

struct irqchip*chip;

struct irqaction *action;

struct

list_head pend;

void*chipdata;

void*data;

unsigned

intdisable_depth;

………….

…………

};

下面分析上面三个重要的成员

chip它是具体中断的操作函数集,如屏蔽开启此中断,设置中断类型。

struct irqchip

{

/*

* Acknowledge the IRQ.

* If this is a level-based IRQ, then it is

expected to mask the IRQ

* as well.

*/

void

(*ack)(unsigned int);

/*

* Mask the IRQ in hardware.

*/

void (*mask)(unsigned int);

/*

* Unmask the IRQ in hardware.

*/

void (*unmask)(unsigned int);

/*

* Ask the hardware to re-trigger the IRQ.

* Note: This method _must_ _not_ call the

interrupt handler.

* If you are unable to retrigger the

interrupt, do not

* provide a function, or if you do, return

non-zero.

*/

int

(*retrigger)(unsigned int);

/*

* Set the type of the IRQ.

*/

int (*type)(unsigned int, unsigned int);//设置中断类型是上升沿还是下降沿

/*

* Set wakeup-enable on the selected IRQ

*/

int

(*wake)(unsigned int, unsigned int);

#ifdef CONFIG_SMP

/*

* Route an interrupt to a CPU

*/

void

(*set_cpu)(struct irqdesc *desc, unsigned int irq, unsigned int cpu);

#endif

};

因此我们可以猜想s3c24xx_init_irq主要是给板子上相应中断赋具体值,事实上就是这样。

void __init s3c24xx_init_irq(void)

{

unsigned

long pend;

unsigned

long last;

int

irqno;

int

i;

irqdbf("s3c2410_init_irq:

clearing interrupt status flags\n");

/*

first, clear all interrupts pending...*/

last = 0;

for (i = 0; i < 4; i++) {

pend =

__raw_readl(S3C2410_EINTPEND);

if

(pend == 0 || pend == last)

break;

__raw_writel(pend,

S3C2410_EINTPEND);

printk("irq:

clearing pending ext status %08x\n", (int)pend);

last

= pend;

}

last

= 0;

for

(i = 0; i < 4; i++) {

pend

= __raw_readl(S3C2410_INTPND);

if

(pend == 0 || pend == last)

break;

__raw_writel(pend,

S3C2410_SRCPND);

__raw_writel(pend,

S3C2410_INTPND);

printk("irq:

clearing pending status %08x\n", (int)pend);

last

= pend;

}

last

= 0;

for

(i = 0; i < 4; i++) {

pend

= __raw_readl(S3C2410_SUBSRCPND);

if

(pend == 0 || pend == last)

break;

printk("irq:

clearing subpending status %08x\n", (int)pend);

__raw_writel(pend,

S3C2410_SUBSRCPND);

last

= pend;

}

/*

register the main interrupts */

irqdbf("s3c2410_init_irq:

registering s3c2410 interrupt handlers\n");

for

(irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) {

/*

set all the s3c2410 internal irqs */

switch

(irqno) {

/*

deal with the special IRQs (cascaded) */

case

IRQ_UART0:

case

IRQ_UART1:

case

IRQ_UART2:

case

IRQ_ADCPARENT:

set_irq_chip(irqno, &s3c_irq_level_chip);

set_irq_handler(irqno, do_level_IRQ);

break;

case

IRQ_RESERVED6:

case

IRQ_RESERVED24:

/*

no IRQ here */

break;

default:

//irqdbf("registering

irq %d (s3c irq)\n", irqno);

set_irq_chip(irqno, &s3c_irq_chip);

set_irq_handler(irqno,

do_edge_IRQ);

set_irq_flags(irqno, IRQF_VALID);

}

}

/*

setup the cascade irq handlers */

set_irq_chained_handler(IRQ_UART0,

s3c_irq_demux_uart0);

set_irq_chained_handler(IRQ_UART1,

s3c_irq_demux_uart1);

set_irq_chained_handler(IRQ_UART2,

s3c_irq_demux_uart2);

set_irq_chained_handler(IRQ_ADCPARENT,

s3c_irq_demux_adc);

/*

external interrupts */

for

(irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {

irqdbf("registering

irq %d (ext int)\n", irqno);

set_irq_chip(irqno,

&s3c_irq_eint0t4);

set_irq_handler(irqno,

do_edge_IRQ);

set_irq_flags(irqno, IRQF_VALID);

}

for (irqno = IRQ_EINT4; irqno <=

IRQ_EINT23; irqno++) {

irqdbf("registering

irq %d (extended s3c irq)\n", irqno);

set_irq_chip(irqno,

&s3c_irqext_chip);

set_irq_handler(irqno,

do_edge_IRQ);

set_irq_flags(irqno, IRQF_VALID);

}

/*

register the uart interrupts */

irqdbf("s3c2410:

registering external interrupts\n");

for

(irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {

irqdbf("registering

irq %d (s3c uart0 irq)\n", irqno);

set_irq_chip(irqno,

&s3c_irq_uart0);

set_irq_handler(irqno,

do_level_IRQ);

set_irq_flags(irqno, IRQF_VALID);

}

for

(irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {

irqdbf("registering

irq %d (s3c uart1 irq)\n", irqno);

set_irq_chip(irqno,

&s3c_irq_uart1);

set_irq_handler(irqno,

do_level_IRQ);

set_irq_flags(irqno, IRQF_VALID);

}

for

(irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {

irqdbf("registering

irq %d (s3c uart2 irq)\n", irqno);

set_irq_chip(irqno,

&s3c_irq_uart2);

set_irq_handler(irqno,

do_level_IRQ);

set_irq_flags(irqno, IRQF_VALID);

}

for (irqno = IRQ_TC; irqno <= IRQ_ADC;

irqno++) {

irqdbf("registering

irq %d (s3c adc irq)\n", irqno);

set_irq_chip(irqno,

&s3c_irq_adc);

set_irq_handler(irqno,

do_edge_IRQ);

set_irq_flags(irqno, IRQF_VALID);

}

irqdbf("s3c2410:

registered interrupt handlers\n");

static struct irqchip s3c_irq_eint0t4 = {

.ack=

s3c_irq_ack,

.mask=

s3c_irq_mask,

.unmask=

s3c_irq_unmask,

.wake=

s3c_irq_wake,

.type= s3c_irqext_type,

};

static ints3c_irqext_type(unsigned int irq, unsigned int type)

{

void

__iomem *extint_reg;

void

__iomem *gpcon_reg;

unsigned

long gpcon_offset, extint_offset;

unsigned

long newvalue = 0, value;

if

((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))

{

gpcon_reg

= S3C2410_GPFCON;

extint_reg

= S3C2410_EXTINT0;

gpcon_offset

= (irq - IRQ_EINT0) * 2;

extint_offset

= (irq - IRQ_EINT0) * 4;

}

else

if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))

{

gpcon_reg

= S3C2410_GPFCON;

extint_reg

= S3C2410_EXTINT0;

gpcon_offset

= (irq - (EXTINT_OFF)) * 2;

extint_offset

= (irq - (EXTINT_OFF)) * 4;

}

else

if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))

{

gpcon_reg

= S3C2410_GPGCON;

extint_reg

= S3C2410_EXTINT1;

gpcon_offset

= (irq - IRQ_EINT8) * 2;

extint_offset

= (irq - IRQ_EINT8) * 4;

}

else

if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))

{

gpcon_reg

= S3C2410_GPGCON;

extint_reg

= S3C2410_EXTINT2;

gpcon_offset

= (irq - IRQ_EINT8) * 2;

extint_offset

= (irq - IRQ_EINT16) * 4;

}

else

return

-1;

/*

Set the GPIO to external interrupt mode */

value

= __raw_readl(gpcon_reg);

value

= (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);

__raw_writel(value,

gpcon_reg);

/*

Set the external interrupt to pointed trigger type */

switch

(type)

{

case

IRQT_NOEDGE:

printk(KERN_WARNING

"No edge setting!\n");

break;

case

IRQT_RISING:

newvalue

= S3C2410_EXTINT_RISEEDGE;

break;

case

IRQT_FALLING:

newvalue

= S3C2410_EXTINT_FALLEDGE;

break;

case

IRQT_BOTHEDGE:

newvalue

= S3C2410_EXTINT_BOTHEDGE;

break;

case

IRQT_LOW:

newvalue

= S3C2410_EXTINT_LOWLEV;

break;

case

IRQT_HIGH:

newvalue

= S3C2410_EXTINT_HILEV;

break;

default:

printk(KERN_ERR

"No such irq type %d", type);

return

-1;

}

value

= __raw_readl(extint_reg);

value

= (value & ~(7 << extint_offset)) | (newvalue <<

extint_offset);

__raw_writel(value,

extint_reg);

return

0;

}

当中断初始化后我们在驱动中要使用中断时,就可以通过request_irq()申请,并且通过set_irq_type设置中断的类型,这个其实是调用具体中断的irq_chip->type函数设置的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值