반응형
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;
}
반응형