복습
isr : interrupt service routin
모든 함수, 구조체에 static을 넣어준다
디바이스 드라이버 만들고 실행시키는 법
1. dev파일, Makefile 작성(우분투)
2. make 실행(우분투)
3. mknod로 device 등록(파이) - 안할 시 no such file
4. insmod로 커널에 적재(파이) - 안할 시 no such device
5. sudo ./파일명 으로 실행(파이) - sudo로 안하면 permision denied
6. rmmod로 커널에서 내림(파이)
데이터 영역은 r/w(전역변수), r/o(상수), static가 잡히고
heap 영역은 malloc으로 잡히고
stack 영역은 지역변수가 잡힌다
전역변수는 종료할 때 까지 메모리에 잡혀있다
지역변수로 잡으면 그 지역 내에서만 사용이 가능하다
그래서 heap 영역에 올라가게 해야 효율적이다
typedef는 컴파일 할 때만 있고 사라진다
포인터 변수는 32비트 아키텍쳐에서 4바이트를 나타낸다
대입 연산자는 왼쪽이 오른쪽보다 크기가 크거나 같아야한다
그렇지 않으면 데이터 손실이 일어날 수 있으니 형변환해서 담아야한다
<포인터 사용의 장점>
힙 영역은 할당하면 free를 해줘야한다
지역변수는 자동으로 사라지기 때문에 auto변수라고도 한다(sp)
매개변수도 지역변수다
char * 배열은 각 글자의 맨 처음글자의 번지수를 리턴한다
어플리케이션은 해제를 안해도 프로세스가 종료되면 회수하는데,
커널은 직접 free를 안하면 아얘 꺼야 종료된다
현재는 실행하고 아무일도 안해도 프로세스의 CPU 점유율이 100%이다
가만 있을 때는 잠들고, 인터럽트가 일어나면 깨어나서 행동하고 다시 잠드는 과정을 반복시킬 것
폴더를 복제한다
~/pi_bsp/drivers$ cp -r p369_ledkey_int_kmalloc p399_ledkey_blockio
스위치를 read 했는데 0이면 키가 안눌린 것이다(데이터가 없다)
그러면 sleep 상태로 보내려 한다
대기 상태로 보냄
리눅스는 기본적으로 blocking으로 열고 NONBLOCK을 잘 사용하지 않음
sleep 상태에서 깬다고 바로 실행하는 것이 아니라 프로세스가 다 끝나야 실행이 된다
read는 많이 대기큐 하지만 write는 잘 안쓰인다
이제 실습해볼 것이다
dev.c 파일을 수정한다
10 #include <linux/wait.h>
36 DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Read);
52 wake_up_interruptible(&WaitQueue_Read);
세개를 수정 및 추가 하고,
read 함수에서 추가해준다
214 // char kbuf;
222 if(pKeyData->keyNumber == 0)
223 {
224 if(!(filp->f_flags & O_NONBLOCK))
225 {
226// wait_event_interruptible(WaitQueue_Read, pKeyData->keyNumber);
227 }
228 }
230 put_user(pKeyData->keyNumber,buf);
app.c를 수정한다
NONBLOCK으로 열면 cpu 점유율 100퍼가 되고
없으면 코드가 멈춰버린다
실행하면
top에도 안보이고, sudo cat /proc/kmsg에도 안보이게 잠들어있다
226// wait_event_interruptible(WaitQueue_Read, pKeyData->keyNumber);
227 wait_event_interruptible_timeout(WaitQueue_Read, pKeyData->keyNu mber, 100); // 100*1/HZ = 100*1/100 = 100*0.01 = 1sec
231 // result = copy_to_user(buf, &(kpKeyData->keyNumber), count);
근데 이렇게 실행하면
top에는 안보이지만 sudo cat /proc/kmsg에 1초에 한번씩 깨어나는 것으로 보인다
어차피 입출력 다중화 함수에서 timeout을 사용할 것이기 때문에 여기서는 다시 주석처리 한다
그리고 이 두 상황은 모두 인터럽트 발생시 정상적으로 깨어난다
폴더를 복사한다
~/pi_bsp/drivers$ cp -r p399_ledkey_blockio p432_ledkey_poll
지금 코드는 read에서 잠들어있어서 key를 안눌렀을 때 led를 절대 킬 수 없다
그리고 다음 코드로 넘어갈 수 없다
이제 키보드로 읽어서 led를 키려고 한다
입력은 여러개인데 원하는 실행은 하나인 경우를 멀티플렉스라고 한다
~/pi_bsp/drivers/p432_ledkey_poll$ cp /mnt/lect_nfs/drivers/ledkey_app_poll.c ledkey_app.c
키보드, 디바이스 드라이브 두개를 입력으로 설정한다
app.c 파일을 본다
19 struct pollfd Events[2]; // 키보드, 디바이스드라이브 두개를 등록할 것이라 2개 선언
43 fflush(stdin); // 쓰레기 값 지우기
44 memset( Events, 0, sizeof(Events)); // 초기화 하는 것
45 Events[0].fd = fileno(stdin); // 표준입력을 키보드로 등록
46 Events[0].events = POLLIN; // 읽기 이벤트 감시하는 것, write는 pollout
47 Events[1].fd = dev;
48 Events[1].events = POLLIN; // 여기까지 등록을 한 것
51 ret = poll(Events, 2, 2000); // 스위치, 키보드 인터럽트가 없으면 2초마다 깨어남(2000 = 2sec)
그리고 오류가 없거나 입력이 없는 것이 아닐 경우 확인한다
62 if(Events[0].revents & POLLIN) //stdin
63 {
64 fgets(keyStr,sizeof(keyStr),stdin);
65 if(keyStr[0] == 'q')
66 break;
67 keyStr[strlen(keyStr)-1] = '\0'; //'\n' clear
68 printf("STDIN : %s\n",keyStr);
69 buff = (char)atoi(keyStr);
70 write(dev,&buff,sizeof(buff));
71 }
72 else if(Events[1].revents & POLLIN) //ledkey
73 {
74 ret = read(dev,&buff,sizeof(buff));
75 printf("key_no : %d\n",buff);
76 if(buff == 8)
77 break;
78 buff = 1 << buff-1;
79 write(dev,&buff,sizeof(buff));
80 }
이제 dev.c를 수정할 것이다
11 #include <linux/poll.h>
290 .poll = ledkey_poll,
file_operations를 검색해서 찾는다
2163 __poll_t (*poll) (struct file *, struct poll_table_struct *);
그래서 다시 dev.c에 가져온다
260 static __poll_t ledkey_poll (struct file * filp, struct poll_table_struct * wait)
261 {
262 unsigned int mask=0;
263 keyData * pKeyData = (keyData *)filp->private_data;
264 #ifdef DEBUG
265 printk("_key : %u\n",(wait->_key & POLLIN));
266 #endif
267 if(wait->_key & POLLIN)
268 poll_wait(filp, &WaitQueue_Read, wait);
269 if(pKeyData->keyNumber > 0)
270 mask = POLLIN;
271 return mask;
272 }
스위치로 0~8, 키보드로 0~255 입력을 통해 잘 되는 것 확인했다