본문 바로가기
카테고리 없음

[Device Driver] proc 파일시스템 사용해서 gpio 제어하기

by TYB 2024. 2. 29.
반응형
ubuntu@ubuntu8:~/pi_bsp/drivers/p527_ledkey_proc$ cat Makefile
APP := p527_ledkey_app
MOD := p527_ledkey_dev
SRC := $(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:$(APP)
        $(MAKE) -C $(KDIR) M=$(PWD) modules $(CROSS)
        cp $(MOD).ko /srv/nfs
$(APP):$(SRC)
        $(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/p527_ledkey_proc$ cat p527_ledkey_app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <poll.h>
#include <string.h>

#define DEVICE_FILENAME "/dev/ledkey_proc"

int main(int argc, char *argv[])
{
        int dev;
        char buff;
        int ret;
        int num = 1;
        struct pollfd Events[2];
        char keyStr[80];

    if(argc != 2)
    {
        printf("Usage : %s [led_data(0x00~0xff)]\n",argv[0]);
        return 1;
    }
    buff = (char)strtoul(argv[1],NULL,16);
//    if(!((0 <= buff) && (buff <= 15)))
    if((buff < 0) || (255 < buff))
    {
        printf("Usage : %s [led_data(0x00~0xff)]\n",argv[0]);
        return 2;
    }

//  dev = open(DEVICE_FILENAME, O_RDWR | O_NONBLOCK);
        dev = open(DEVICE_FILENAME, O_RDWR );
        if(dev < 0)
        {
                perror("open");
                return 2;
        }
        write(dev,&buff,sizeof(buff));

        fflush(stdin);
        memset( Events, 0, sizeof(Events));
        Events[0].fd = fileno(stdin);
        Events[0].events = POLLIN;
        Events[1].fd = dev;
        Events[1].events = POLLIN;
        while(1)
        {
                ret = poll(Events, 2, 2000);
                if(ret<0)
                {
                        perror("poll");
                        exit(1);
                }
                else if(ret==0)
                {
                        printf("poll time out : %d Sec\n",2*num++);
                        continue;
                }
                if(Events[0].revents & POLLIN)  //stdin
                {
                        fgets(keyStr,sizeof(keyStr),stdin);
                        if(keyStr[0] == 'q')
                                break;
                        keyStr[strlen(keyStr)-1] = '\0';
                        printf("STDIN : %s\n",keyStr);
                        buff = (char)atoi(keyStr);
                        write(dev,&buff,sizeof(buff));
                }
                else if(Events[1].revents & POLLIN) //ledkey
                {
                        ret = read(dev,&buff,sizeof(buff));
                        buff = 1 << buff-1;
                        printf("key_no : %d\n",buff);
                        write(dev,&buff,sizeof(buff));
                        if(buff == 0x80)
                                break;
                }
        }
        close(dev);
        return 0;
}
ubuntu@ubuntu8:~/pi_bsp/drivers/p527_ledkey_proc$ cat p527_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/moduleparam.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>

#define gpioName(a,b) #a#b     //"led""0" == "led0"
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
#define OFF 0
#define ON 1

#define   LED_DEV_NAME            "ledkeydev"
#define   LED_DEV_MAJOR            230
#define DEBUG 1

DECLARE_WAIT_QUEUE_HEAD(WaitQueue_Read);
static unsigned long ledvalue = 15;
static char * twostring = NULL;
static int sw_irq[8] = {0};
static char sw_no = 0;

static struct proc_dir_entry *keyledproc_root_fp   = NULL;
static struct proc_dir_entry *keyledproc_led_fp    = NULL;
static struct proc_dir_entry *keyledproc_key_fp    = NULL;

module_param(ledvalue, ulong ,0);
module_param(twostring,charp,0);

int gpioLed[GPIOLEDCNT] = {6,7,8,9,10,11,12,13};
int gpioKey[GPIOKEYCNT] = {16,17,18,19,20,21,22,23};

int gpioLedInit(void);
void gpioLedSet(long);
void gpioLedFree(void);
int gpioKeyInit(void);
int gpioKeyGet(void);
void gpioKeyFree(void);

int     gpioLedInit(void)
{
        int i;
        int ret = 0;
        for(i=0;i<GPIOLEDCNT;i++)
        {
                ret = gpio_request(gpioLed[i], gpioName(led,i));
                if(ret < 0) {
                        printk("Failed Request gpio%d error\n", 6);
                        return ret;
                }
        }
        for(i=0;i<GPIOLEDCNT;i++)
        {
                ret = gpio_direction_output(gpioLed[i], OFF);
                if(ret < 0) {
                        printk("Failed direction_output gpio%d error\n", 6);
         return ret;
                }
        }
        return ret;
}

void gpioLedSet(long val)
{
        int i;
        for(i=0;i<GPIOLEDCNT;i++)
        {
                gpio_set_value(gpioLed[i], (val>>i) & 0x01);
        }
}
void gpioLedFree(void)
{
        int i;
        for(i=0;i<GPIOLEDCNT;i++)
        {
                gpio_free(gpioLed[i]);
        }
}

int gpioKeyInit(void)
{
        int i;
        int ret=0;;
        for(i=0;i<GPIOKEYCNT;i++)
        {
                ret = gpio_request(gpioKey[i], gpioName(key,i));
                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;
}
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;
        }
        return keyData;
}
void gpioKeyFree(void)
{
        int i;
        for(i=0;i<GPIOKEYCNT;i++)
        {
                gpio_free(gpioKey[i]);
        }
}


static void gpioKeyToIrq(void)
{
        int i;
    for (i = 0; i < GPIOKEYCNT; i++) {
        sw_irq[i] = gpio_to_irq(gpioKey[i]);
        }
}

static void gpioKeyFreeIrq(void)
{
        int i;
        for (i = 0; i < GPIOKEYCNT; i++){
                free_irq(sw_irq[i],NULL);
        }
}

int ledkeydev_open (struct inode *inode, struct file *filp)
{
    int num0 = MAJOR(inode->i_rdev);
    int num1 = MINOR(inode->i_rdev);
    printk( "ledkeydev open -> major : %d\n", num0 );
    printk( "ledkeydev open -> minor : %d\n", num1 );

    return 0;
}

ssize_t ledkeydev_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
//      char kbuf;
        int ret;
#if DEBUG
    printk( "ledkeydev read -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
#endif
//      kbuf = gpioKeyGet();

        if(!(filp->f_flags & O_NONBLOCK))  //BLOCK Mode
        {
                if(sw_no == 0)
                        wait_event_interruptible(WaitQueue_Read,sw_no);
//              wait_event_interruptible_timeout(WaitQueue_Read,sw_no,100); //100: 1/100 *100 = 1Sec

        }
        ret=copy_to_user(buf,&sw_no,count);
        sw_no = 0;
        if(ret < 0)
                return -ENOMEM;
    return count;
}

ssize_t ledkeydev_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
        char kbuf;
        int ret;
#if DEBUG
    printk( "ledkeydev write -> buf : %08X, count : %08X \n", (unsigned int)buf, count );
#endif
        ret=copy_from_user(&kbuf,buf,count);
        if(ret < 0)
                return -ENOMEM;
        gpioLedSet(kbuf);
    return count;
}

static long ledkeydev_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
{

#if DEBUG
    printk( "ledkeydev ioctl -> cmd : %08X, arg : %08X \n", cmd, (unsigned int)arg );
#endif
    return 0;
}
static unsigned int ledkeydev_poll(struct file * filp, struct poll_table_struct * wait)
{
        unsigned int mask = 0;
        printk("_key : %u \n",(wait->_key & POLLIN));
        if(wait->_key & POLLIN)
                poll_wait(filp, &WaitQueue_Read, wait);
        if(sw_no > 0)
                mask = POLLIN;
        return mask;
}

int ledkeydev_release (struct inode *inode, struct file *filp)
{
    printk( "ledkeydev release \n" );
    return 0;
}

struct file_operations ledkeydev_fops =
{
    .owner    = THIS_MODULE,
    .open     = ledkeydev_open,
    .read     = ledkeydev_read,
    .write    = ledkeydev_write,
        .unlocked_ioctl = ledkeydev_ioctl,
        .poll     = ledkeydev_poll,
    .release  = ledkeydev_release,
};

irqreturn_t sw_isr(int irq, void *unuse)
{
        int i;
        for(i=0;i<GPIOKEYCNT;i++)
        {
                if(irq == sw_irq[i])
                {
                        sw_no = i+1;
                        break;
                }
        }
        printk("IRQ : %d, sw_no : %d\n",irq,sw_no);
        wake_up_interruptible(&WaitQueue_Read);
        return IRQ_HANDLED;
}
static ssize_t proc_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
        char kbuf[10];
        int ret;
        int len=0;
        kbuf[0] = sw_no+0x30;
        kbuf[1] = '\n';
        kbuf[2] = 0;
        len = strlen(kbuf);
        ret=copy_to_user(buf,kbuf,len);
        sw_no = 0;
        *f_pos = -1;
    return len;
}

static ssize_t proc_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
        char kbuf[10];
        int ret;
//      get_user(kbuf,buf);
//      printk("count %d %s\n",count,buf);
        ret=copy_from_user(kbuf,buf,count);
        gpioLedSet(simple_strtoul(kbuf,NULL,10));
    return count;
//      return -EFAULT;
}
struct  proc_ops proc_led_fops =
{
    .proc_write    = proc_write,
};
struct  proc_ops proc_key_fops =
{
    .proc_read     = proc_read,
};

static void mkproc(void)
{
        keyledproc_root_fp  = proc_mkdir( "ledkey", 0 );

        keyledproc_led_fp   = proc_create_data( "led", S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO, keyledproc_root_fp, &proc_led_fops, NULL);
        keyledproc_key_fp   = proc_create_data( "key", S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO, keyledproc_root_fp, &proc_key_fops, NULL);
}

static void rmproc(void)
{
        remove_proc_entry( "led"  , keyledproc_root_fp );
        remove_proc_entry( "key"  , keyledproc_root_fp );
        remove_proc_entry( "ledkey" , 0 );
}
int ledkeydev_init(void)
{
    int result=0;
        int i;

    printk( "ledkeydev ledkeydev_init \n" );

    result = register_chrdev( LED_DEV_MAJOR, LED_DEV_NAME, &ledkeydev_fops);
    if (result < 0) return result;

        result = gpioLedInit();
        if(result < 0)
                return result;     /* Device or resource busy */

        result = gpioKeyInit();
        if(result < 0)
                return result;     /* Device or resource busy */
        gpioKeyToIrq();

        for(i=0;i<GPIOKEYCNT;i++)
        {
                result = request_irq(sw_irq[i],sw_isr,IRQF_TRIGGER_RISING,gpioName(key,i),NULL);
                if(result)
                {
                        printk("#### FAILED Request irq %d. error : %d \n", sw_irq[i], result);
                        break;
                }
        }
        mkproc();
    return result;
}

void ledkeydev_exit(void)
{
    printk( "ledkeydev ledkeydev_exit \n" );
    unregister_chrdev( LED_DEV_MAJOR, LED_DEV_NAME );
        rmproc();
        gpioLedFree();
        gpioKeyFreeIrq();
        gpioKeyFree();
}

module_init(ledkeydev_init);
module_exit(ledkeydev_exit);

MODULE_AUTHOR("KCCI-AIOT KSH");
MODULE_DESCRIPTION("led key test module");
MODULE_LICENSE("Dual BSD/GPL");

 

make 하고 라즈베리파이에서 

mknod /dev/ledkeydev c 230 0

insmod p527_ledkey_dev.ko

sudo chmod 666 /dev/ledkeydev

 

./ p527_ledkey_app 0xf0

 

sudo echo "85" > /proc/ledkey/led

 

cat /proc/ledkey/key

 

이때까지 proc 밑에 많은 정보를 봤는데 proc에 echo 명령어를 날려서 gpio를 제어하는 코드임.

 


 

/proc/ledkey/led 

 

proc file system을 이용해서 gpio 값을 읽을 수도 있다는 거

 

ubuntu@ubuntu8:~/pi_bsp/drivers/p527_ledkey_proc$ cat proc_test_app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <poll.h>
#include <string.h>

#define DEVICE_LED_FILENAME "/proc/ledkey/led"
#define DEVICE_KEY_FILENAME "/proc/ledkey/key"

int main(int argc, char *argv[])
{
        int ledFd;
        int keyFd;
        char buff[10]={0};

        if(argc < 2)
        {
                printf("Usage : %s [0~15]\n",argv[0]);
                return 1;
        }

        ledFd = open(DEVICE_LED_FILENAME, O_WRONLY );
        if(ledFd < 0)
        {
                perror("open1");
                return 2;
        }
        keyFd = open(DEVICE_KEY_FILENAME, O_RDONLY );
        if(keyFd < 0)
        {
                perror("open2");
                return 3;
        }
        strcpy(buff,argv[1]);
        write(ledFd,buff,strlen(buff));
        printf("write : %s\n",buff);
        memset(buff,0,sizeof(buff));
        read(keyFd,buff,sizeof(buff));
        printf("read : %s\n",buff);
        close(ledFd);
        close(keyFd);
        return 0;
}

 

 

 

 

반응형