디바이스 드라이버를 개발할 때 하드웨어에서 발생하는 정보를 얻기 위해서는 주기적으로 하드웨어를 검사(폴링)하거나 인터럽트를 사용해야 한다.
폴링은 불필요한 CPU자원을 계속 낭비할 수 있기 때문에 하드웨어에서 언제 정보가 발생하는지 알 수 없을 경우에는 인터럽트를 사용하는 것이 훨씬 효율적이다.
여기에서는 인터럽트 관련된 내용을 살펴 보도록 하겠다.
인터럽트는 CPU 아키텍쳐에 따라서 처리하는 방식이 많이 다르기 때문에 여기에서는 커널에서 인터럽트를 접근하는 측면에서 살펴보도록 하겠다.
일단, 현재 커널에 등록되어 있는 인터럽트 핸들러들의 리스트를 보기 위해서는 /proc/interrupts 파일을 살펴보면 된다.
인터럽트의 활성화/비활성화
경우에 따라서 인터럽트로부터의 방해를 받고 싶지 않을 수가 있다. 이러한 경우에는 인터럽트 금지 함수를 사용해서 인터럽트가 CPU로 전달되지 않도록 하면 된다. 관련 함수들은 다음과 같다.
#include <asm/irq.h>
void local_irq_disable(void);
void local_irq_enable(void);
void disable_irq(int irq);
void disable_irq_nosync(int irq);
void enabled_irq(int irq);
local_irq_disable(), local_irq_enable() 함수는 모든 IRQ 인터럽트를 막는 것이며, 아래 함수들은 특정 IRQ만 금지하는 명령이다. 이 함수들은 CPU에게 명령을 내려서 CPU가 처리하지 않도록 하는 것이기 때문에 다른 CPU에 인터럽트가 전달되는 것은 막을 수 없다.
인터럽트 핸들러 작성
리눅스에서는 인터럽트 디스크립터 테이블(IDP)를 직접 건드리지 않는다. IDP는 부팅시 초기화 된 이후에는 변경되지 않으며, 디바이스 드라이버 등에서는 리눅스에서 잡아놓은 환경위에서 동작하게 된다. 인터럽트 핸들러를 다루기 위해서는 다음 함수들을 사용한다.
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags,
const char *devname, void *dev_id);
void free_irq(unsigned int irq, void *dev_id);
인터럽트 핸들러를 특정 번호에 등록하기 위해서는 request_irq 함수를 사용하면 된다. 이때, irq 번호에 원하는 인터럽트 번호를 지정하고, handler에는 나중에 수행될 인터럽트 핸들러를 지정하면 된다. irqflags는 핸들러의 특성을 지정할 수 있다. devname은 /proc/interrupts에서 확인할 수 있는 핸들러의 이름이다.
인터럽트 핸들러 함수의 프로토타입은 2.4와 2.6에서 약간 차이가 있다. 다음은 2.4에서의 인터럽트 핸들러 함수 프로토타입니다.
void my_interrupt(int irq, void *dev_id, struct pt_regs *regs);
2.6에서는 먼저 인터럽트 핸들러에 리턴값을 반환하도록 변형되었는데, 2.6.19부터는 마지막 인수도 제거되었다. 따라서, 2.6.19 이후의 버전에서는 다음과 같은 형태가 된다.
irqreturn_t my_interrupt(int irq, void *dev_id);
irqreturn_t는 인터럽트 처리를 했는지 안했는지를 나타내는데, IRQ_NONE이나 IRQ_HANDLED를 사용하면 된다.
'Linux > API' 카테고리의 다른 글
| I/O Port 다루기 on x86 (0) | 2008/01/26 |
|---|---|
| 인터럽트 (0) | 2008/01/25 |
| 커널 시간 관리 (0) | 2008/01/25 |
| CPU별 변수 사용 (0) | 2007/10/08 |
이올린에 북마크하기
이올린에 추천하기

