본문 바로가기
Linux BSP

[Linux Device Driver] Device Driver와 application으로 led, 버튼 제어

by TYB 2024. 2. 23.
반응형

 

폴더 새로 만들고 그 안에 c코드 추가

ubuntu@ubuntu8:~/pi_bsp/drivers/p238_ledkey$ vi ledkey_app.c

 

일단 application부터 만들어봅시다.

 

system call 함수 만들 때 썼던 코드 재활용합시다.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <asm-generic/unistd.h>
#pragma GCC diagnostic ignored "-Wunused-result"


int main(int argc, char *argv[])
{
        unsigned int val=0, key_data,key_data_old=0;
        int i;
        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;
        }
        do {
                usleep(100000);  //100MSec
                key_data = syscall(__NR_mysyscall,val);
                if(key_data != key_data_old)
                {
                        key_data_old = key_data;
                        if(key_data)
                        {
                                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;
}

 

코드 수정이 좀 필요한데 아래처럼 파일 open하는 부분을 추가하믄 됨.

#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;
}

 

 


dev 파일

ubuntu@ubuntu8:~/pi_bsp/drivers/p238_ledkey$ vi ledkey_dev.c

이전 글에서 썼던 call_dev.c를 들고와서 수정

:%s/call/ledkey/g&nbsp; 를 하면 자동으로 변경됨.

:%s/CALL/LEDKEY/g 도 해주시고 ~

 

#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)
{
    printk( "ledkey read -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
    return 0x33;
}

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);
*/
    printk( "ledkey write -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
        get_user(kbuff,buf);
//      result = copy_from_user(&kbuff,buf,count);
        gpioLedSet(kbuff);
    return 0x43;
}

//int ledkey_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
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");

 

p106폴더의 ledkey.c의 내용을 복사하자.

:1,152w gpio.txt 명령을 사용하여 1부터 1,152번 줄까지의 내용을 다른 파일로 저장할 수 있습니다.

 

:r gpio.txt현재 커서 위치에 다른 파일의 내용을 붙여넣을 수 있습니다.

 

 


Makefile도 수정

APP과 MOD를 ledkey로 변경

APP := ledkey_app
MOD := ledkey_dev
SRC := $(APP).c
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:$(APP)
        $(MAKE) -C $(KDIR) M=$(PWD) modules $(CROSS)
        cp $(MOD).ko /srv/nfs
$(APP):
        $(CC) $(APP).c -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)

 

 

ubuntu@ubuntu8:~/pi_bsp/drivers/p238_ledkey$ make

 

라즈베리파이로 넘어가서

pi@pi08:/mnt/ubuntu_nfs $ sudo mknod /dev/ledkey c 230 0
pi@pi08:/mnt/ubuntu_nfs $ sudo insmod ledkey_dev.ko
pi@pi08:/mnt/ubuntu_nfs $ sudo ./ledkey_app
USAGE : ./ledkey_app ledVal[0x00~0xff]
pi@pi08:/mnt/ubuntu_nfs $ sudo ./ledkey_app 0xff
TEST00
TEST01
0:1:2:3:4:5:6:7
O:O:O:O:O:O:O:O

처음 프로그램 실행할 때 매개변수로 들어오는 값만큼 led를 켜주고, 버튼에 매칭되는 led키고 8번째 버튼 눌리면 프로그램 종료

lsmod를 쳐보면 ledkey_dev 디바이스 드라이버 모듈의 호출 횟수가 나와야됨. 종료되면 다시 0으로 리셋되야 되고

 

 

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;
    printk( "ledkey read -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
        kbuf = (char)gpioKeyGet();
        put_user(kbuf,buf);
    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[10];
        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);
        gpioLedSet(kbuff);
    return 0x43;
}

//int ledkey_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
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;
        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;
}

 

ubuntu@ubuntu8:~/pi_bsp/drivers/p238_ledkey/p238_ledkey$ make

 

pi@pi08:~ $ lsmod | grep led
Module                  Size  Used by
ledkey_dev             16384  1

 

pi@pi08:~ $ lsmod |grep led
ledkey_dev             16384  0
반응형