도와주세요!!
안녕하세요 AU1200 보드로 이것저것 TEST 진행중인 리눅스 초보 개발자 입니다.
제가 책보고 GPIO26 번 ( 보드에서 TACT 스위치 연결 ) 입력 인터럽트 드라이버를 시험중인데요
몇가지 질문이 있습니다.
irq_request 함수 전달 인수중에 첫번째 irq 전달 인수가 인터럽트 번호로 알고 있습니다. 그래서 현재 커널이
사용하고 있는 인터럽트 번호를 피하기 위해 cat /proc/interrupts 명령을 실행해서 아래 결과를 얻었습니다.
CPU0
2 : 7 Au1000 Level MMC
3 : 0 Au1000 Level Au1xxx dbdma
29: 1 Au1000 Level ehci_hcd: usb1, ohci_hcd:usb2
30: 0 Au1000 Level lcd
34: 92 Au1000 Fall Edge eth0
42: 0 Au1000 Level wm9712 TouchScreen 0.30
ERR 0
1.
상기 결과에서 좌측에 있는 번호( 2,3,29........)가 현재 등록된 인터럽트 서비스 함수 번호로 알고 있습니다.
그러면 사용자가 인터럽트 서비스 함수를 등록할때 상기 번호를 제외한 임의 번호를 아무 제약없이
사용 가능한건가요? 책을 보면 이 부분에 대한 내용이 자세히 나와 있지 않네요
그런데 문제가 현재 TEST를 해보면 , 상기 번호를 피한다고 해서 다 등록이 되는게 아니던데요
TEST 결과로는 " 7 " 번의 경우 현재 점유하지 않는 번호인데 insmod 로 드라이버 등록시 인터럽트
서비스 함수가 등록이 않되구요 다른 번호중에도 그런게 있습니다. 그러면 사용자가 프로그램 작성할때
일일이 등록해서 되는지 않되는지 확인해 보고 결정해야 되는건지, 아니면 뭔가 다른 방법이 있는건지요
2. 인터럽트 번호를 "10"으로 지정한후 insmod로 드라이버를 적재 한후 cat /proc/interrupts 로 확인해서 아래 결과
를 얻었습니다.
CPU0
2 : 7 Au1000 Level MMC
3 : 0 Au1000 Level Au1xxx dbdma
10: 0 Au1000 Level int1dev <---------------------------------------- 등록된거 맞나요?
29: 1 Au1000 Level ehci_hcd: usb1, ohci_hcd:usb2
30: 0 Au1000 Level lcd
34: 92 Au1000 Fall Edge eth0
42: 0 Au1000 Level wm9712 TouchScreen 0.30
ERR 0
상기 결과로 보면 일단 좌측에 10 번이 추가 됐고 우측에 지정된 드라이버 명이 나오는걸로 봐서 정상 등록이
된거 같은데 맞는지요 ? 그리고 나서 GPIO 26번을 Falling edge 인터럽트로 입력으로 설정한후 보드 Dip 스위치를
누르면 아래 메세지가 계속 출력 됩니다.
unexpected IRQ # 58
irq 58, desc: 804c1e80, depth: 1, count: 0, unhandled: 0
->handle_irq(): 80151390, handle_bad_irq+0x0/0x34c
->chip(): 804861f0, 0x804861f0
->action(): 00000000
IRQ_DISABLED set
일단 상기 메세지가 계속 출력되는건 한번 걸린 인터럽트가 소거가 안되서 인터럽트가 계속걸리는거 같습니다.
맞나요? 실제 확인해보면 제가 만든 인터럽트 서비스 함수가 실행이 않되는거 같습니다.
그리고 상기 내용중에 unexpected IRQ #58 에서
IRQ #58이면 등록된 인터럽트 번호가 58 번이라는 얘긴가요? 저는 분명히 " 10 " 으로 등록했는데 왜 58 번으로
표시 되는거죠??
조언 부탁드립니다.
IRQ_GPIO 함수를 찾지 못하겠네요 일단 au1200 에서 #include <asm/gpio> 선언시 컴파일 에러가 생기구요
커널 소스 파일에서 arm 관련 파일에서 IRQ_GPIO 함수를 찾아 봤는데 못찾겠어요
인터럽트 발생시 출력되는 에러 메세지 중에
unexpected IRQ # 58
---> 인터럽트가 발생된 GPIO 포트에 해당하는 인터럽트 번호가 커널에 58번으로 지정되 있는데
사용자 작성 프로그램에서 인터럽트 서비스를 등록할때 다른 번호로 등록했기 때문에 인터럽트 발생시
서비스 루틴을 찾지 못해 상기 메세지가 출력 되는 건가요 ?
----> request_irq(.....) 함수에서 인터럽트 번호를 58번으로 설정하면 등록이 안되는데... 그렇다면 그것도 아
닌거 같고 난감 하네요 ^^ 답변 부탁 드립니다.
저의 경우 au1200 에서는 아래와 같이 사용합니다.
irq = gpio_nr + 32;
32 를 더한것은 커널에서 gpio 로 지원되는 인터럽트의 시작을 32 부터 시작하기 때문입니다.
또하나 주의 할점은 irq 의 형태, 상승,하강 엣지나 어떤 레벨일때 인터럽트가 걸릴것인가에 대한 정의입니다.
arm 코아아 mips 에서의 정의가 달라 mips 일경우는 아래와 같이 코딩하였습니다.
참고로 arm, mips 모두 컴파일이 가능하도록 하기 위해 아래와 같이 하였음을 알려드립니다.
case FA_IRQT_NONE : irq_type = 0; break;
case FA_IRQT_LOW : irq_type = 6; break;
case FA_IRQT_HIGH : irq_type = 5; break;
case FA_IRQT_UP : irq_type = 1; break;
case FA_IRQT_DOWN : irq_type = 2; break;
set_irq_type( irq, irq_type )
request_irq() 함수는 반드시 써야 합니다.
request_irq() 함수 호출 후 어떤 에러가 나는지 궁금하군요
사용하는 irq 번호가 이미 사용된것은 아닌지 살펴보세요
테스트중 irq 번호가 사용상태에서 해제하지 않고 나왔다면 등록이 되지 않습니다.
이런 경우 리부팅이 필요합니다.
request_irq() 함수 사용시 들어가는 인자들을 모두 보여주시면 디버깅에 도움이 되겠네요
http://forum.falinux.com/zbxe/?mid=Kernel_API&document_srl=503472&listStyle=&cpage=
현재 등록된 인터럽트 번호를 확인해 보면 다음과 같습니다.
[root@falinux intdev]$ cat /proc/interrupts
CPU0
2: 7 Au1000 Level MMC
3: 0 Au1000 Level Au1xxx dbdma
29: 1 Au1000 Level ehci_hcd:usb1, ohci_hcd:usb2
30: 0 Au1000 Level lcd
34: 493 Au1000 Fall Edge eth0
42: 0 Au1000 Level wm9712 TouchScreen 0.30
ERR: 0
-------------------------------------------------------------------------------------------------
TEST 파일 내용
-------------------------------------------------------------------------------------------------
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include </project/falinux/kernel/linux/include/asm-mips/mach-au1x00/au1000.h>
#include </jjyprog/work/Kseg1RegMap.h>
void Int_Init(void);
int Int_init(void);
int Int_open(struct inode *inode,struct file *filp);
void Int_Clear(void);
int Int_release(struct inode *inode,struct file *filp);
int Test;
struct file_operations int_fos=
{
.owner=THIS_MODULE,
.open=Int_open,
.release=Int_release,
};
//------------------------------------------------------------------------------------
//- 인터럽트 서비스 함수 !
//------------------------------------------------------------------------------------
irqreturn_t Int_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
printk(" interrupt event !! n");
Int_Clear();
return
IRQ_HANDLED;
}
int Int_open(struct inode *inode,struct file *filp)
{
int Result;
printk(" Int dev Open ! n");
return
Result;
}
int Int_release(struct inode *inode,struct file *filp)
{
printk(" interrupt release ! n");
//---------------------------------------
//- 인터럽트 서비스 함수 해제 !
//---------------------------------------
free_irq(IRQ_GPIO_1,NULL);
//---------------------------------------
return
0;
}
int Int_init(void)
{
int result;
int result_sub;
int irq_num;
result=register_chrdev(DEV_INT1_MAJOR,DEV_NAME_INT1,&int_fos);
if(result<0) return result;
else{
result_sub=request_irq(IRQ_GPIO_1,Int_interrupt,SA_INTERRUPT,DEV_NAME_INT1,NULL);
if(result_sub==0){
printk(" request irq Set ! n");
//-----------------------------------------------------
//- Falling Edge Enable !
//-----------------------------------------------------
*((volatile unsigned long *)IC1_CFG2CLR)=1<<14;
*((volatile unsigned long *)IC1_CFG1SET)=1<<14;
*((volatile unsigned long *)IC1_CFG0CLR)=1<<14;
//-----------------------------------------------------
//- Falling Edge Detect bit clear !
//-----------------------------------------------------
*((volatile unsigned long *)IC1_FALLINGCLR)=1<<14;
//-----------------------------------------------------
//- Use the peripheral interrupt or GPIO signal
//- as interrupt source !
//-----------------------------------------------------
*((volatile unsigned long *)IC1_SRCSET)=1<<14;
//-----------------------------------------------------
//- Assigns interrupt to request 1 ???
//-----------------------------------------------------
*((volatile unsigned long *)IC1_ASSIGNSET)=1<<14;
//-----------------------------------------------------
//- interrupt enable
//-----------------------------------------------------
*((volatile unsigned long *)IC1_MASKSET)=1<<14;
}
else{
printk(" Irq request error=%d n",result_sub);
}
}
return 0;
}
void Int_Clear(void)
{
*((volatile unsigned long *)IC1_FALLINGCLR)=1<<14;
}
void Int_exit(void)
{
unregister_chrdev(DEV_INT1_MAJOR,DEV_NAME_INT1);
//-----------------------------------------------------
//- interrupt disable
//-----------------------------------------------------
*((volatile unsigned long *)IC1_MASKCLR)=1<<14;
//-----------------------------------------------------
printk(" Int1 dev remove !! n");
//---------------------------------------
//- 인터럽트 서비스 함수 해제 !
//---------------------------------------
free_irq(IRQ_GPIO_1,NULL);
//---------------------------------------
}
module_init(Int_init);
module_exit(Int_exit);
MODULE_LICENSE("Dual BSD/GPL");
-------------------------------------------------------------------------------------------------------------------------------------
상기 내용에서 RQ_GPIO_1 는 헤더파일에서 46으로 정의 했구요
insmod로 드라이버를 적재하면 다음 에러 메세지가 보입니다.
Irq request error=-89
--------------------------------------------------------------------------------------------------------------------------------------
뭔가 잘못됐나요???????
인터럽트 에지설정이나 활성화는 set_irq_type() 함수를 사용하세요
<asm/irq.h> 파일을 포함하면 됩니다.
에러값에 -89는 이해가 되지않는 값이네요
커널쪽 request_irq() 소스에서는 위의 값을 넘겨주는 루틴이 없어 애매합니다.
테스트를 해바야 알것 같네요 ㅡ.ㅡ
에휴 시간이 허락할지 ....
커널소스를 보면
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
......................................
......................................
retval = setup_irq(irq, action); <====================
return retval
}
int setup_irq(unsigned int irq, struct irqaction *new)
{
..................................................
if (desc->chip == &no_irq_chip)
return -ENOSYS; <================ ENOSYS 값이 89로 표시되네요
}
request_irq 관련 커널 소스에서 89값을 돌려주는 부분은 상기 표시 부분외에는 없는것으로 보입니다.
그렇다면 위 구문은 어떤경우에 실행 되는건가요???
gpio 번호에 대응하는 irq 번호가 커널에 등록되어 있습니다.
아래의 함수를 사용하여 irq 번호를 얻어오세요
irq = IRQ_GPIO( gp_nr );