저번 예제에는 1byte를 application에 넘겨서 write를 하는 거였는데, 8byte 배열을 넘겨보자.
보통 디바이스 드라이버에서 1바이트만 넘기지는 않음.
sudo mknod ledkey_array
기존 app 코드
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#pragma GCC diagnostic ignored "-Wunused-result"
int main(int argc, char *argv[])
{
char buff;
int i;
int ledkeyfd;
int key_data,key_data_old=0;
unsigned long val=0;
if(argc < 2)
{
printf("USAGE : %s ledVal[0x00~0xff]\n",argv[0]);
return 1;
}
val = strtoul(argv[1],NULL,16);
if(val<0 || 0xff<val)
{
printf("Usage : %s ledValue[0x00~0xff]\n",argv[0]);
return 2;
}
ledkeyfd = open("/dev/ledkey",O_RDWR|O_NONBLOCK);
if(ledkeyfd < 0)
{
perror("open()");
return 1;
}
buff = (char)val;
printf("TEST00\n");
write(ledkeyfd, &buff, sizeof(buff));
printf("TEST01\n");
do {
usleep(100000); //100MSec
// key_data = syscall(__NR_mysyscall,val);
read(ledkeyfd, &buff, sizeof(buff));
key_data = buff;
if(key_data != key_data_old)
{
key_data_old = key_data;
if(key_data)
{
write(ledkeyfd, &buff, sizeof(buff));
//val = key_data;
puts("0:1:2:3:4:5:6:7");
for(i=0;i<8;i++)
{
if(key_data & (0x01 << i))
putchar('O');
else
putchar('X');
if(i != 7 )
putchar(':');
else
putchar('\n');
}
putchar('\n');
}
if(key_data == 0x80)
break;
}
}while(1);
printf("mysyscall return value = %#04x\n",key_data);
return 0;
}
매개변수로 들어오는 0x00~0xff의 1byte 값을 8byte로 바꾸겠음.
8바이트로 수정-> 이렇게 하면 실행파일 실행 할 때 입력은 1바이트 인데, 넘길 때는 8바이트가 되서 디바이스 드라이버 dev파일의 write함수에 8byte가 넘어감.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#pragma GCC diagnostic ignored "-Wunused-result"
int main(int argc, char *argv[])
{
char buff[8];
int i;
int ledkeyfd;
int key_data,key_data_old=0;
unsigned long val=0;
if(argc < 2)
{
printf("USAGE : %s ledVal[0x00~0xff]\n",argv[0]);
return 1;
}
val = strtoul(argv[1],NULL,16);
if(val<0 || 0xff<val)
{
printf("Usage : %s ledValue[0x00~0xff]\n",argv[0]);
return 2;
}
ledkeyfd = open("/dev/ledkey",O_RDWR|O_NONBLOCK);
if(ledkeyfd < 0)
{
perror("open()");
return 1;
}
// buff = (char)val;
for(i = 0; i < 8; i++)
{
buff[i] = (val >> i) & 0x01;
}
printf("TEST00\n");
write(ledkeyfd, buff, sizeof(buff));
printf("TEST01\n");
do {
usleep(100000); //100MSec
// key_data = syscall(__NR_mysyscall,val);
read(ledkeyfd, &buff, sizeof(buff));
key_data = buff;
if(key_data != key_data_old)
{
key_data_old = key_data;
if(key_data)
{
write(ledkeyfd, &buff, sizeof(buff));
//val = key_data;
puts("0:1:2:3:4:5:6:7");
for(i=0;i<8;i++)
{
if(key_data & (0x01 << i))
putchar('O');
else
putchar('X');
if(i != 7 )
putchar(':');
else
putchar('\n');
}
putchar('\n');
}
if(key_data == 0x80)
break;
}
}while(1);
printf("mysyscall return value = %#04x\n",key_data);
return 0;
}
dev.c의 기존 wrtie함수를 살펴보니 gpioLedSet에 들어가는 값이 long임.
gpio는 손대지 말고, 8바이트로 받은 걸 다시 1바이트로 변환해주면 되겠죠?
ez~
139 ssize_t ledkey_write (struct file *filp, const char *buf, size_t count, loff _t *f_pos)
140 {
141 // int i;
142 int result;
143 char kbuff;
144 /* char kbuff[10];
145 for(i=0;i<count;i++)
146 get_user(kbuff[i],buf++);
147 */
148 /* char kbuff[10];
149 copy_from_user(kbuff,buf,count);
150 */
151 printk( "ledkey write -> buf : %08X, count : %08X \n", (unsigned int)buf , count );
152 get_user(kbuff,buf);
153 // result = copy_from_user(&kbuff,buf,count);
154 gpioLedSet(kbuff);
155 return 0x43;
156 }
8byte를 받아야 하므로, 주석처리된 부분을 해제하면 됨.
char를 char 배열로 바꿔주고 8바이트 char를 1바이트로 바꿔줄 바이트 데이터를 하나 만들어주면됨.
pi@pi08:/mnt/ubuntu_nfs $ sudo mknod /dev/ledkey c 230 0
pi@pi08:/mnt/ubuntu_nfs $ sudo insmod ledkey_array_dev.ko
pi@pi08:/mnt/ubuntu_nfs $ sudo ./ledkey_array_app 0xff
ubuntu make clean ; make
pi@pi08:/mnt/ubuntu_nfs $ sudo rmmod ledkey_array_dev.ko
pi@pi08:/mnt/ubuntu_nfs $ sudo ./ledkey_array_app 0xff
write 수정했으니까, read도 수정하자.
아래는 read까지 수정 후 코드들.
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>
#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};
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 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]);
}
}
int ledkey_open (struct inode *inode, struct file *filp)
{
int num0 = MAJOR(inode->i_rdev);
int num1 = MINOR(inode->i_rdev);
printk( "ledkey open -> major : %d\n", num0 );
printk( "ledkey open -> minor : %d\n", num1 );
try_module_get(THIS_MODULE);
return 0;
}
loff_t ledkey_llseek (struct file *filp, loff_t off, int whence )
{
printk( "ledkey llseek -> off : %08X, whenec : %08X\n", (unsigned int)off, whence );
return 0x23;
}
ssize_t ledkey_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
char kbuf[8];
int i;
int keyVal;
int result;
printk( "ledkey read -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
keyVal = (char)gpioKeyGet();
for(i=0;i<count;i++)
{
kbuf[i] = (keyVal >> i) & 0x01;
}
// put_user(kbuf,buf);
result = copy_to_user(buf, kbuf, count);
return count;
}
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[8];
long ledVal=0;
/* for(i=0;i<count;i++)
get_user(kbuff[i],buf++);
*/
/* char kbuff[10];
copy_from_user(kbuff,buf,count);
*/
printk( "ledkey write -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
// get_user(kbuff,buf);
result = copy_from_user(kbuff,buf,count);
for(i=0;i<8;i++)
{
ledVal = ledVal | (kbuff[i] << i);
}
gpioLedSet(ledVal);
return count;
}
static long ledkey_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
{
printk( "ledkey ioctl -> cmd : %08X, arg : %08X \n", cmd, (unsigned int)arg );
return 0x53;
}
int ledkey_release (struct inode *inode, struct file *filp)
{
printk( "ledkey release \n" );
module_put(THIS_MODULE);
return 0;
}
struct file_operations ledkey_fops =
{
// .owner = THIS_MODULE,
.open = ledkey_open,
.read = ledkey_read,
.write = ledkey_write,
.unlocked_ioctl = ledkey_ioctl,
.llseek = ledkey_llseek,
.release = ledkey_release,
};
int ledkey_init(void)
{
int result;
printk( "ledkey ledkey_init \n" );
result=gpioLedInit();
if(result < 0)
return result;
result=gpioKeyInit();
if(result < 0)
return result;
result = register_chrdev( LEDKEY_DEV_MAJOR, LEDKEY_DEV_NAME, &ledkey_fops);
if (result < 0) return result;
return 0;
}
void ledkey_exit(void)
{
printk( "ledkey ledkey_exit \n" );
unregister_chrdev( LEDKEY_DEV_MAJOR, LEDKEY_DEV_NAME );
gpioLedFree();
gpioKeyFree();
}
module_init(ledkey_init);
module_exit(ledkey_exit);
MODULE_LICENSE("Dual BSD/GPL");
app.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#pragma GCC diagnostic ignored "-Wunused-result"
int main(int argc, char *argv[])
{
char buff[8];
int i;
int ledkeyfd;
int key_data=0,key_data_old=0;
unsigned long val=0;
if(argc < 2)
{
printf("USAGE : %s ledVal[0x00~0xff]\n",argv[0]);
return 1;
}
val = strtoul(argv[1],NULL,16);
if(val<0 || 0xff<val)
{
printf("Usage : %s ledValue[0x00~0xff]\n",argv[0]);
return 2;
}
ledkeyfd = open("/dev/ledkey",O_RDWR|O_NONBLOCK);
if(ledkeyfd < 0)
{
perror("open()");
return 1;
}
// buff = (char)val;
for(i=0;i<8;i++)
{
buff[i] = (val >> i) & 0x01;
}
write(ledkeyfd, buff, sizeof(buff));
do {
usleep(100000); //100MSec
key_data = 0;
read(ledkeyfd,buff,sizeof(buff));
for(i=0;i<8;i++)
{
/* if(buff[i] == 1)
{
key_data = i+1;
break;
}
*/
key_data = key_data | (buff[i] << i);
}
if(key_data != key_data_old)
{
key_data_old = key_data;
if(key_data)
{
write(ledkeyfd, &buff, sizeof(buff));
puts("0:1:2:3:4:5:6:7");
for(i=0;i<8;i++)
{
if(key_data & (0x01 << i))
putchar('O');
else
putchar('X');
if(i != 7 )
putchar(':');
else
putchar('\n');
}
putchar('\n');
}
if(key_data == 0x80)
break;
}
}while(1);
printf("mysyscall return value = %#04x\n",key_data);
return 0;
}
Makefile
APP := ledkey_array_app
MOD := ledkey_array_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)
지금은 시간 sleep을 줘서 커널이 처리하는 인터럽트 핸들러에서 일정 시간이 지나면, TIMEOUT에 의해서 다시 프로그램 동작시키고 있는데, sleep을 안주면 top에서 cpu 코어1의 사용량이 100%를 찍는다. sleep을 주면 core1이 5%정도 점유하고 있음.
그래서 추후에, block io를 활용해서 cpu 사용량을 0%에 수렴하게 바꿔버리겠음.
'Linux BSP' 카테고리의 다른 글
[Device Driver] ioctl 함수 (1) | 2024.02.26 |
---|---|
[Linux Device Driver] 주번호, 부번호의 개념과 예제 (1) | 2024.02.26 |
[Linux Device Driver] Device Driver와 application으로 led, 버튼 제어 (0) | 2024.02.23 |
[Linux Device Driver] 디바이스 드라이버 (0) | 2024.02.23 |
[Raspberry Pi Device Driver] 디바이스 드라이버(app과 dev)를 통한 device 제어 (0) | 2024.02.22 |