컴퓨터공부/Linux & Unix

request_irq, setup_arm_irq

achivenKakao 2007. 3. 28. 13:01
SA에서 GPIO 11~27의 interrupt service routine
글쓴이 : 초보 (2003년 07월 17일 오후 09:56) 읽은수: 761 [ 질문과답변 인쇄용 페이지 ]
안녕하세요. 너그러이 답변 부탁드립니다. ^^;
SA의 GPIO(PXA도 마찬가지입니다만)에서 11~27은 rising 또는 falling edge가
뜨면 irq를 발생시키고 다음의 interrupt handler를 구동시킵니다.
여기까지 맞나요?

void sa1100_GPIO11_27_demux(int irq, void *dev_id,struct pt_regs *regs)
{
.....
(irq = (GEDR & 0xfffff800))
....

for (i = 11; i <= 27; ++i) {
if (irq & (1<> do_IRQ (IRQ_GPIO_11_27(i), regs);
}
}

그러면, 이 handler 내에서는 GDER을 조사해서 어느 GPIO핀에서 edge가
떴는지 조사해서 해당 ISR을 수행해야 할텐데요. 이것이 위의 코드에서는
do_IRQ()인 것 같은데요. 이 함수에 제가 원하는 ISR 코드를 넣어 주고 싶은데,
어디에서 하는 지 모르겠습니다.
도움 말씀 바랍니다.

SA에서 GPIO 11~27의 interrupt service routine | 답장: 4개(RSS) | 본문에 답장
정렬 :  
답장 안영수 (2003년 07월 18일 오전 12:15)
집에서는 리눅스를 사용하지 않는 상태라 소스가 없네요..
vmware 써서 한번 깔아볼려니 네트웍이 잘 안되네요.

예전 기억으로는 리눅스 소스에서
grep -r do_IRQ * 로 찾으면, arch/arm 쪽에서 찾았던 것 같습니다.
CPU 마다 다르기 때문에 arch안에 있고...
아마도 C로 짰다면, void do_IRQ(어쩌고 저쩌고)일테니
grep -r 'void do_IRQ' * 하시면, 찾기 쉬울겁니다.

어셈이라면,
grep -r '^do_IRQ' * 하면 나올 가능성이 높고요.

그런데 이게 왜 필요하신지 모르겠네요.
이 함수가 하는 역할은 interrupt가 들어오면, request_irq로 등록된 함수를 호출해 주는 것 밖에 없는데요.
interrupt기 때문에 다른 interrupt를 막는 등의 역할은 해주겠지만, 필요한 일이 있다면 request_irq로 등록하는 함수에서 하는 것이 정상적인데요.


----
음....
grep -r 'void do_IRQ' * 로 했더니...
arch/arm/kernel/irq.c네요.
[ 이글에 답장 | 본문에 답장 ]

답장 초보 (2003년 07월 18일 오전 10:01)
답변 감사합니다.
do_IRQ()가 request_irq()로 등록된 ISR을 호출해 주는 일을 한다고 하셨습니다.
그럼, 제가 GPIO중 pin 20 에서만 인터럽트를 처리해주려고 할때 다음의 내용이 맞나요?
(GPIO 20에 대한 핸들러를 myhandler()로 하겠습니다.)

- sa1100_GPIO11_27_demux()는 GPIO 11~ 27까지의 OR된 interrupt의 handler이며
set_arm_irq()을 통해 등록한다.

- GEDR을 decode하여 GPIO 20에서의 interrupt발생을 확인하여 호출하는 myhandler()는
request_irq()를 통해 등록한다.

또, set_arm_irq와 request_irq의 차이를 잘 모르겠습니다. 특정 irq(interrupt request)
에 대해 handler 함수를 설정해주는 것이 아닌가요?
[ 이글에 답장 | 본문에 답장 ]

답장 안영수 (2003년 07월 18일 오후 01:53)
irq_desc가 interrupt가 들어왔을 때 처리할 handler와 기타 정보를 가진 구조체입니다.

request_irq() :
action이라는 놈을 만들고 있습니다.
action은 그냥 handler와 device 정보등을 가지고 있는 구조체네요.
!irq_desc[irq].valid로 정상적인지 확인은 하지만, irq_desc에 직접 수정은 하지 않습니다.
action->handler = handler; -> handler를 action에 넣었네요.
그리고 실제 등록 함수인 setup_arm_irq() 호출.


setup_arm_irq() :
desc = irq_desc + irq;
p = &desc->action;
*p = new;
해석을 위해 중요한 건 위 세줄인걸로 보입니다.
irq_desc의 irq 위치에 request_irq()에서 만든 action(new)을 넣고 있습니다.
기타 여러줄의 코드가 있지만, 추적할 때는 기억할 게 많으면, 헤매게 되니 생략하겠습니다.


do_IRQ() :
desc = irq_desc + irq;
action = desc->action;
action->handler(irq, action->dev_id, regs);
irq_desc에서 irq번째에 있는 action을 찾아서 handler를 실행합니다.


interrupt를 처리하는 방식은 CPU마다 다름니다.
그런데 OS는 CPU에 관계없이 device driver에게 동일한 환경을 제공해야 합니다.
request_irq가 일반적으로 interrupt 사용을 요구하는 함수이고, setup_arm_irq는 실질적으로 등록하는 함수이지만, 내부적으로 사용하는 함수입니다.
즉 setup_arm_irq는 다른 device driver에서 호출하기를 원하지 않는 함수입니다.
(호출하면, arm이 아닌 다른 CPU 상의 리눅스에는 setup_arm_irq()가 없을 가능성이 높기 때문에 system 의존성이 생깁니다)

그리고 일반적으로는 setup_arm_irq 같이 CPU 의존적인 부분은 arch/arm 쪽에,
request_irq 같은 경우, 공통으로 사용할 상위 interface이기 때문에 kernel에 있는 경우가 많습니다.
그런데 request_irq의 경우 다른 CPU의 request 함수를 보시면, 알겠지만, struct irqaction이 조금씩 다른 경우가 있습니다.
그래서 cpu 의존적이 되었기 때문에(함수 원형은 같기때문에 사용자 interface는 같습니다) arch/arm으로 이사온 것 뿐입니다.



----
sa1100_GPIO11_27_demux()는 GPIO 11~ 27까지의 OR된 interrupt의 handler이며
set_arm_irq()을 통해 등록한다.

-->>

이걸 말로 설명하려니 좀 애매한데...
strong arm은 interrupt를 받을 수 있는 register의 크기는 한정되어 있고(32개), 받아야할 interrupt는 많고(32 + GPIO 11~27 - 1 == 48개) 해서, 일부 interrupt는 demux 과정을 거치도록 되어있습니다.

CPU는 11~27까지의 GPIO에서 interrupt가 발생할 경우, IRQ_GPIO11_27 (11번) 한곳으로만 들어오는 구조로 되어있습니다.
OS는 이걸 실제 몇번에서 들어왔는지 확인하기 위해, request_irq()에서 원하는 handler를 IRQ_GPIO11_27에 직접 다는 대신 sa1100_GPIO11_27_demux()를 달아두고, 이 demux에서 GEDR로 확인한 다음 실제 그 interrupt에 맞는 handler를 호출해주게 됩니다.

예를 들면,
irq 33 (GPIO 12번)의 경우, request_irq에 지정한 handler를 irq_desc[33]에 달아 둡니다.
GPIO 12번에 interrupt가 발생하면, 실제 interrupt는 CPU 구조상 IRQ_GPIO11_27번(GPIO 11번)으로 들어오고, sa1100_GPIO11_27_demux()가 handler로 호출됩니다.
(이건 sa1100_init_irq() 함수 안에, setup_arm_irq( IRQ_GPIO11_27, &GPIO11_27_irq ); 에서 등록합니다.)
이 sa1100_GPIO11_27_demux()에서 GEDR 확인해 보고, GPIO 12번(IRQ 33)이 set이면, irq_desc[33]에 있는 handler를 호출하는 식입니다.

irq11~27 (irq 32~48)이 이 과정을 거칩니다. 나머지는 1:1로 매치되기 때문에 irq번호로 irq_desc에서 찾아서 바로 호출됩니다.
OR를 어떤 뜻으로 사용했는지 모르지만, 그 함수는 말 그대로 demux 입니다.

multiplex랑 demultiplex랑 햇갈리네요. 둘 중 하나의 개념인데...


set_arm_irq()는 위에 설명대로, 실질적으로 등록하는 함수이지만, device driver에서는 request_irq를 통해 접근하는 것이 좋습니다.


------
설명도 애매하고...
말은 길어지고...
잘못된 부분이 있을 수도 있는데, 확인도 안해보고....
옛날에 봤던 부분인데, 오랜만에 보니 헤매네요....
그냥 참고만 하세요.
[ 이글에 답장 | 본문에 답장 ]

답장 초보 (2003년 07월 18일 오후 03:04)
자세한 답변에 대해 깊이 감사드립니다.

말씀하신 내용중에서 제가 궁금해하던 내용이 보이는 군요.

>CPU는 11~27까지의 GPIO에서 interrupt가 발생할 경우, IRQ_GPIO11_27 (11번) 한곳으로만 들어오는 구조로 되어있습니다.
>OS는 이걸 실제 몇번에서 들어왔는지 확인하기 위해, request_irq()에서 원하는 handler를 IRQ_GPIO11_27에 직접 다는 대신 sa1100_GPIO11_27_demux()를 달아두고, 이 demux에서 GEDR로 확인한 다음 실제 그 interrupt에 맞는 handler를 호출해주게 됩니다.

>예를 들면,
>irq 33 (GPIO 12번)의 경우, request_irq에 지정한 handler를 irq_desc[33]에 달아 둡니다.
>GPIO 12번에 interrupt가 발생하면, 실제 interrupt는 CPU 구조상 IRQ_GPIO11_27번(GPIO 11번)으로 들어오고, sa1100_GPIO11_27_demux()가 handler로 호출됩니다.
>(이건 sa1100_init_irq() 함수 안에, setup_arm_irq( IRQ_GPIO11_27, &GPIO11_27_irq ); 에서 등록합니다.)
>이 sa1100_GPIO11_27_demux()에서 GEDR 확인해 보고, GPIO 12번(IRQ 33)이 set이면, irq_desc[33]에 있는 handler를 호출하는 식입니다.

즐거운 오후되세요.
출처 : http://kelp.or.kr/korweblog/stories.php?story=03/07/17/6603461&cmode=&comment_sort=asc&p=1