반응형
이전 글에서의 문제점은 잠들지 않고 지속적으로 폴링을 하고 있는 프로세스 때문에 top을 쳤을 때 cpu 점유율이 100%라는 점인데, 프로세스를 sleep 상태로 만들어서 cpu 사용량을 0%로 만드는 것이 목표임.
이전글 코드 복사해서 그대로 사용하겠음.
키를 읽었는데, 키값이 0이다? => process를 sleep(block) 상태로 보냄.
키가 눌렸다면 ISR 호출하고 ISR이 리턴되기 전에 Read함수에서 재웠던 process를 깨워서 다시 키 값을 읽어서 return하면됨.
Nonblock이니까 open할 때 O_NDELAY 옵션을 주면 안됨.
대기 큐 변수를 사용해야 하는데, 이를 위해 사용하는 함수와 변수들이 있음.
프로세스를 재울 때 사용하는 함수
프로세스를 깨울 때 사용하는 함수
dev.c 수정
yyp 한줄 복사 밑 아랫줄에 붙여넣기
cw 한단어 지우면서 입력모드
키가 눌릴 때 까지 잠들어 있는거까지 구현했음. 이제 깨워줄 친구를 찾아줘야겠죠?
Makefile
APP := ledkey_app
MOD := ledkey_dev
OBJ := $(APP).o
obj-m := $(MOD).o
CROSS = ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
CC := arm-linux-gnueabihf-gcc
KDIR := /home/ubuntu/pi_bsp/kernel/linux
PWD := $(shell pwd)
default:$(OBJ)
$(MAKE) -C $(KDIR) M=$(PWD) modules $(CROSS)
cp $(MOD).ko /srv/nfs
%.o:%.c
$(CC) -o $(APP) $<
cp $(APP) /srv/nfs
clean:
rm -rf *.ko
rm -rf *.mod.*
rm -rf .*.cmd
rm -rf *.o
rm -rf modules.order
rm -rf Module.symvers
rm -rf $(MOD).mod
rm -rf .tmp_versions
rm -rf $(APP)
app.c
ubuntu@ubuntu8:~/pi_bsp/drivers/p399_ledkey_blockio$ cat ledkey_app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define DEVICE_FILENAME "/dev/ledkey_dev"
void print_OX(unsigned char);
int main(int argc,char * argv[])
{
char buff = 0;
char oldBuff = 0;
int dev;
int ret;
unsigned long val;
if(argc < 2)
{
printf("Usage : %s ledValue[0x00~0xff]\n",argv[0]);
return 1;
}
val = strtoul(argv[1],0,16);
if(val<0 || 0xff<val)
{
printf("Usage : %s ledValue[0x00~0xff]\n",argv[0]);
return 2;
}
buff = val;
// dev = open( DEVICE_FILENAME, O_RDWR|O_NONBLOCK );
dev = open( DEVICE_FILENAME, O_RDWR );
if(dev<0)
{
perror("open()");
return 2;
}
ret = write(dev,&buff,sizeof(buff));
if(ret < 0)
{
perror("write()");
return 3;
}
buff = 0;
do {
read(dev,&buff,sizeof(buff));
if(oldBuff != buff)
{
if(buff != 0)
{
printf("key : %d\n",buff);
print_OX(buff);
write(dev,&buff,sizeof(buff));
if(buff == 8) //key:8
break;
}
oldBuff = buff;
}
} while(1);
close(dev);
return 0;
}
void print_OX(unsigned char led)
{
int i;
led = 1 << led-1;
puts("1:2:3:4:5:6:7:8");
for(i=0;i<=7;i++)
{
if(led & (0x01 << i))
putchar('O');
else
putchar('X');
if(i < 7 )
putchar(':');
else
putchar('\n');
}
return;
}
dev.c
ubuntu@ubuntu8:~/pi_bsp/drivers/p399_ledkey_blockio$ cat ledkey_dev.c
#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 <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/wait.h>
#define DEBUG 1
#define LEDKEY_DEV_NAME "ledkey_dev"
#define LEDKEY_DEV_MAJOR 230
#define OFF 0
#define ON 1
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
static int gpioLed[GPIOLEDCNT] = {6,7,8,9,10,11,12,13};
static int gpioKey[GPIOKEYCNT] = {16,17,18,19,20,21,22,23};
typedef struct {
int key_irq[8];
int keyNumber;
} keyData;
static int gpioLedInit(void);
static void gpioLedSet(long);
static void gpioLedFree(void);
static int gpioKeyInit(void);
//static int gpioKeyGet(void);
static void gpioKeyFree(void);
static int gpioKeyIrqInit(keyData * pKeyData);
static void gpioKeyIrqFree(keyData * pKeyData);
DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Read);
static irqreturn_t key_isr(int irq, void *data)
{
int i;
keyData * pKeyData = (keyData *)data;
for(i=0;i<GPIOKEYCNT;i++)
{
if(irq == pKeyData->key_irq[i])
{
pKeyData->keyNumber = i+1;
break;
}
}
#if DEBUG
printk("key_isr() irq : %d, KeyNumber : %d\n",irq, pKeyData->keyNumber);
#endif
wake_up_interruptible(&WaitQueue_Read);
return IRQ_HANDLED;
}
static int gpioLedInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOLEDCNT;i++)
{
sprintf(gpioName,"led%d",i);
ret = gpio_request(gpioLed[i],gpioName);
if(ret < 0) {
printk("Failed gpio_request() gpio%d error \n",i);
return ret;
}
ret = gpio_direction_output(gpioLed[i],OFF);
if(ret < 0) {
printk("Failed gpio_direction_output() gpio%d error \n",i);
return ret;
}
}
return ret;
}
static void gpioLedSet(long val)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_set_value(gpioLed[i],(val>>i) & 0x1);
}
}
static void gpioLedFree(void)
{
int i;
for(i=0;i<GPIOLEDCNT;i++)
{
gpio_free(gpioLed[i]);
}
}
static int gpioKeyInit(void)
{
int i;
int ret=0;
char gpioName[10];
for(i=0;i<GPIOKEYCNT;i++)
{
sprintf(gpioName,"key%d",gpioKey[i]);
ret = gpio_request(gpioKey[i], gpioName);
if(ret < 0) {
printk("Failed Request gpio%d error\n", 6);
return ret;
}
}
for(i=0;i<GPIOKEYCNT;i++)
{
ret = gpio_direction_input(gpioKey[i]);
if(ret < 0) {
printk("Failed direction_output gpio%d error\n", 6);
return ret;
}
}
return ret;
}
/*
static int gpioKeyGet(void)
{
int i;
int ret;
int keyData=0;
for(i=0;i<GPIOKEYCNT;i++)
{
// ret=gpio_get_value(gpioKey[i]) << i;
// keyData |= ret;
ret=gpio_get_value(gpioKey[i]);
keyData = keyData | ( ret << i );
}
return keyData;
}
*/
static void gpioKeyFree(void)
{
int i;
for(i=0;i<GPIOKEYCNT;i++)
{
gpio_free(gpioKey[i]);
}
}
static int gpioKeyIrqInit(keyData * pKeyData)
{
int i;
int result;
char * irqName[8] = {"IrqKey0","IrqKey1","IrqKey2","IrqKey3","IrqKey4","IrqKey5","IrqKey6","IrqKey7"};
for(i=0;i<GPIOKEYCNT;i++)
{
pKeyData->key_irq[i] = gpio_to_irq(gpioKey[i]);
if(pKeyData->key_irq[i] < 0)
{
printk("gpioKeyIrq() Failed gpio %d\n",gpioKey[i]);
return pKeyData->key_irq[i];
}
}
for(i=0;i<GPIOKEYCNT;i++)
{
result = request_irq(pKeyData->key_irq[i],key_isr,IRQF_TRIGGER_RISING,irqName[i],pKeyData);
if(result < 0)
{
printk("request_irq() failed irq %d\n",pKeyData->key_irq[i]);
return result;
}
}
return 0;
}
static void gpioKeyIrqFree(keyData * pKeyData)
{
int i;
for(i=0;i<GPIOKEYCNT;i++)
{
free_irq(pKeyData->key_irq[i],pKeyData);
}
}
static int ledkey_open (struct inode *inode, struct file *filp)
{
int result;
int num0 = MAJOR(inode->i_rdev);
int num1 = MINOR(inode->i_rdev);
keyData * pKeyData = (keyData *)kmalloc(sizeof(keyData),GFP_KERNEL);
if(!pKeyData)
return -ENOMEM;
pKeyData->keyNumber = 0;
#if DEBUG
printk( "ledkey open -> major : %d\n", num0 );
printk( "ledkey open -> minor : %d\n", num1 );
#endif
try_module_get(THIS_MODULE);
result=gpioLedInit();
if(result < 0)
return result;
result=gpioKeyInit();
if(result < 0)
return result;
result = gpioKeyIrqInit(pKeyData);
if(result < 0)
return result;
filp->private_data = pKeyData;
return 0;
}
static ssize_t ledkey_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
// int result;
// char kbuf;
keyData * pKeyData = (keyData *)filp->private_data;
#if DEBUG
printk( "ledkey read -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
#endif
// kbuf = (char)gpioKeyGet();
// kbuf = pKeyData->keyNumber;
if(pKeyData->keyNumber == 0)
{
if(!(filp->f_flags & O_NONBLOCK))
{
wait_event_interruptible(WaitQueue_Read,pKeyData->keyNumber);
}
}
put_user(pKeyData->keyNumber,buf);
if(pKeyData->keyNumber)
pKeyData->keyNumber = 0;
// result = copy_to_user(buf, &kbuf, count);
return count;
}
static ssize_t ledkey_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
// int i;
// int result;
char kbuff;
/* char kbuff[10];
for(i=0;i<count;i++)
get_user(kbuff[i],buf++);
*/
/* char kbuff[10];
copy_from_user(kbuff,buf,count);
*/
#if DEBUG
printk( "ledkey write -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
#endif
get_user(kbuff,buf);
// result = copy_from_user(&kbuff,buf,count);
gpioLedSet(kbuff);
return count;
}
static long ledkey_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
{
#if DEBUG
printk( "ledkey ioctl -> cmd : %08X, arg : %08X \n", cmd, (unsigned int)arg );
#endif
return 0x53;
}
static int ledkey_release (struct inode *inode, struct file *filp)
{
keyData * pKeyData = (keyData *)filp->private_data;
#if DEBUG
printk( "ledkey release \n" );
#endif
module_put(THIS_MODULE);
gpioKeyIrqFree(pKeyData);
gpioKeyFree();
gpioLedFree();
if(pKeyData)
kfree(pKeyData);
return 0;
}
static struct file_operations ledkey_fops =
{
// .owner = THIS_MODULE,
.open = ledkey_open,
.read = ledkey_read,
.write = ledkey_write,
.unlocked_ioctl = ledkey_ioctl,
.release = ledkey_release,
};
static int ledkey_init(void)
{
int result;
printk( "ledkey ledkey_init \n" );
result = register_chrdev( LEDKEY_DEV_MAJOR, LEDKEY_DEV_NAME, &ledkey_fops);
if (result < 0) return result;
return 0;
}
static void ledkey_exit(void)
{
printk( "ledkey ledkey_exit \n" );
unregister_chrdev( LEDKEY_DEV_MAJOR, LEDKEY_DEV_NAME );
}
module_init(ledkey_init);
module_exit(ledkey_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("KCCI-AIOT KSH");
MODULE_DESCRIPTION("led key test module");
ledkey_app 프로세스 상태보는거
pi@pi08:~ $ ps -auwx | grep ledkey_app
Time-Out Interrupt
228 wait_event_interruptible(WaitQueue_Read,pKeyData->keyNumber); 라인의 내용을 아래의 내용으로 바꾸면
wait_event_interruptible_timeout(WaitQueue_Read,pKeyData->keyNumber,100); //100 * 1/HZ = 100 * 1/100 = 100 * 0.01 = 1Sec
sudo cat /proc/kmsg
1초마다 인터럽트가 발생해서 kernel message 출력되는걸 확인 가능
더 발전시켜봅싀당.
반응형
'Linux BSP' 카테고리의 다른 글
[Device Driver] 커널 타이머 GPIO제어하는 모듈 프로그램 디바이스 드라이버 프로그램으로 바꾸기 (0) | 2024.02.28 |
---|---|
[Linux Device Driver] 입출력 다중화 (1) | 2024.02.28 |
[Linux Device Driver] 커널 메모리 동적 할당 및 irq매개변수를 통한 인터럽트 데이터 전달 (1) | 2024.02.27 |
[Linux Device Driver] Interrupt 처리 (0) | 2024.02.27 |
[Linux Device Driver] Timer Interrupt (0) | 2024.02.27 |