linux驱动之----多节点编程实战

简介

实现功能:按键按下控制LED灯亮灭
实现思想:
KEY驱动层:
使用Linux2.6方式注册,自动注册设备文件
Linux中断判断按键按下,Linux定时器实现按键消抖
等待队列实现用户端的阻塞IO提高cpu利用率。
KEY的用户层:
使用4个线程分别读取按键的状态,read无按键按下时候阻塞
使用消息队列和LED用户层通信,发送按键信息
LED驱动层:
使用杂项注册设备
LED用户层:
接收KEY用户层发送的按键信息,控制LED灯的亮灭

代码实现

KEY驱动层:key.c

#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>//中断头文件
#include <linux/gpio.h>//GPIO头文件
#include <linux/irq.h>//中断触发边沿头文件
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/timer.h>//定时器头文件
/*
	GPX3_2 -- KEY1
	GPX3_3 -- KEY2
	GPX3_4 -- KEY3
	GPX3_4 -- KEY4
	 GPX3CON -- 0x1100_0000	+  0x0C60
	 GPX3DAT -- 0x1100_0000 + 0x0C64
*/
unsigned int * key_base = NULL;

#define GPX3CON  *((volatile unsigned int *) (key_base))
#define GPX3DAT  *((volatile unsigned int *) (key_base+1))
static DECLARE_WAIT_QUEUE_HEAD(key1_wait);
static DECLARE_WAIT_QUEUE_HEAD(key2_wait);
static DECLARE_WAIT_QUEUE_HEAD(key3_wait);
static DECLARE_WAIT_QUEUE_HEAD(key4_wait);
int cond1 =0;
int cond2 =0;
int cond3 =0;
int cond4 =0;
dev_t my_dev;
struct cdev my_cdev;
struct file_operations oper;
struct class * cl;
struct timer_list my_time;
struct key_msg
{
	char * name;
	int key_value;
	int minor;

	uint32_t irq_num;//中断编号
	uint32_t gpio_num;//外部引脚编号
};
struct key_msg key_buf[4]={
	{"key1",1,0,0,EXYNOS4_GPX3(2)},
	{"key2",2,0,0,EXYNOS4_GPX3(3)},
	{"key3",3,0,0,EXYNOS4_GPX3(4)},
	{"key4",4,0,0,EXYNOS4_GPX3(5)}
};
void timer_fuction(unsigned long data)
{
  if(!(GPX3DAT & (0X01<<2)))
  {
	wake_up_interruptible(&key1_wait);
	cond1=1;
  }
  if(!(GPX3DAT & (0X01<<3)))
  {
	wake_up_interruptible(&key2_wait);
	cond2=1;
  } 
    if(!(GPX3DAT & (0X01<<4)))
  {
	wake_up_interruptible(&key3_wait);
	cond3=1;
  } 
    if(!(GPX3DAT & (0X01<<5)))
  {
	wake_up_interruptible(&key4_wait);
	cond4=1;
  } 
}

irqreturn_t interrupt_fuction(int num, void * arg)//num为传入的中断编号
{
  
  printk("num==%d\n",num);
  mod_timer(&my_time,jiffies+msecs_to_jiffies(15));

  return 0;
}
int key_open(struct inode * inode, struct file * file)
{
	int mi = MINOR(inode->i_rdev);//提取次设备号
	static int a=0;
	if(mi ==key_buf[0].minor)//按键1
	{	
		key_buf[0].irq_num = gpio_to_irq(key_buf[0].gpio_num);//获取中断编号
		enable_irq(key_buf[0].irq_num);
		a=request_irq(key_buf[0].irq_num,interrupt_fuction,IRQ_TYPE_EDGE_FALLING,"key",NULL);//注册中断
		file->private_data = (void *)&key_buf[0];
	}else if(mi ==key_buf[1].minor)//按键2
	{
		key_buf[1].irq_num = gpio_to_irq(key_buf[1].gpio_num);//获取中断编号
		enable_irq(key_buf[1].irq_num);
		a=request_irq(key_buf[1].irq_num,interrupt_fuction,IRQ_TYPE_EDGE_FALLING,"key",NULL);

		file->private_data = (void *)&key_buf[1];
	}
	else if(mi ==key_buf[2].minor)//按键3
	{
		key_buf[2].irq_num = gpio_to_irq(key_buf[2].gpio_num);//获取中断编号
		enable_irq(key_buf[2].irq_num);
		a=request_irq(key_buf[2].irq_num,interrupt_fuction,IRQ_TYPE_EDGE_FALLING,"key",NULL);

		file->private_data = (void *)&key_buf[2];
	}
	else if(mi ==key_buf[3].minor)//按键4
	{
		key_buf[3].irq_num = gpio_to_irq(key_buf[3].gpio_num);//获取中断编号
		enable_irq(key_buf[3].irq_num);
		a=request_irq(key_buf[3].irq_num,interrupt_fuction,IRQ_TYPE_EDGE_FALLING,"key",NULL);

		file->private_data = (void *)&key_buf[3];
	}
	return 0;
}
int key_close(struct inode * inode, struct file * file)
{
	free_irq(key_buf[0].irq_num, NULL);//释放中断
	free_irq(key_buf[1].irq_num, NULL);
	free_irq(key_buf[2].irq_num, NULL);
	free_irq(key_buf[3].irq_num, NULL);

	disable_irq(key_buf[0].irq_num);//注销
	disable_irq(key_buf[1].irq_num);
	disable_irq(key_buf[2].irq_num);
	disable_irq(key_buf[3].irq_num);
	return 0;
}
ssize_t key_read(struct file * file, char __user * buf, size_t size, loff_t * offt)
{
	struct key_msg * tmp = (struct key_msg *) file->private_data;
        unsigned long a;
	if(tmp->key_value == 1)//按键1
	{
	 if(!cond1)
	 {
		wait_event_interruptible(key1_wait, cond1);//阻塞
		a =copy_to_user(buf,&tmp->key_value,4);
		cond1=0;
	 }
	 else
	 {
		cond1=0;
	 }
	}
	if(tmp->key_value == 2)//按键1
	{
	if(!cond2)
	 {
		wait_event_interruptible(key2_wait, cond2);//阻塞
		a =copy_to_user(buf,&tmp->key_value,4);
		cond2=0;
	 }
	 else
	 {
		cond2=0;
	 }
	}
	if(tmp->key_value == 3)//按键1
	{
	if(!cond3)
	 {
		wait_event_interruptible(key3_wait, cond3);//阻塞
		a =copy_to_user(buf,&tmp->key_value,4);
		cond3=0;
	 }
	 else
	 {
		cond3=0;
	 }
	}
	if(tmp->key_value == 4)//按键1
	{
	 if(!cond4)
	 {
		wait_event_interruptible(key4_wait, cond4);//阻塞
		a =copy_to_user(buf,&tmp->key_value,4);
		cond4=0;
	 }
	 else
	 {
		cond4=0;
	 }
	}
	return 0;
}
static int __init key1_init(void)
{
	my_time.expires=jiffies+HZ;
	my_time.function=timer_fuction;
	my_time.data=0;
	init_timer(&my_time);
	//1:申请设备号
	alloc_chrdev_region(&my_dev,0,4,"KEY");
	//2:注册设备
	oper.open = key_open;
	oper.release = key_close;
	oper.read = key_read;
	cdev_init(&my_cdev,&oper);
	cdev_add(&my_cdev,my_dev,4);
	//3:自动注册设备
	cl = class_create(THIS_MODULE,"KEY");
	device_create(cl,NULL,my_dev,NULL,"key1");
	key_buf[0].minor = MINOR(my_dev);
	device_create(cl,NULL,my_dev+1,NULL,"key2");
	key_buf[1].minor = MINOR(my_dev+1);
	device_create(cl,NULL,my_dev+2,NULL,"key3");
	key_buf[2].minor = MINOR(my_dev+2);
	device_create(cl,NULL,my_dev+3,NULL,"key4");
	key_buf[3].minor = MINOR(my_dev+3);
	//4:地址重映射
	key_base = ioremap(0x11000C60,0x8);
	GPX3CON&=~(0x0F<<8); //输入模式
	return 0;
}

static void __exit key_exit(void)
{
}

module_init(key1_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");

KEY用户层:key_app.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/msg.h>
void * text1(void * arg);
void * text2(void * arg);
void * text3(void * arg);
void * text4(void * arg);
char buf[1024] = {0};
struct message
{
	long msg_type;
	int key_num;
};

int key_name=0;
struct message msg;
int msg_pid=0;
int main(int argc,char * argv[])
{
		
    pthread_t pthread_id[4]={0};
	msg.msg_type=getpid();
	msg_pid=msgget(ftok("./key.c",0),IPC_CREAT|0777);
	pthread_create(&pthread_id[0],NULL,text1,NULL);	
	pthread_create(&pthread_id[1],NULL,text2,NULL);	
	pthread_create(&pthread_id[2],NULL,text3,NULL);	
	pthread_create(&pthread_id[3],NULL,text4,NULL);	

	pthread_join(pthread_id[0],NULL);
	pthread_join(pthread_id[1],NULL);
	pthread_join(pthread_id[2],NULL);
	pthread_join(pthread_id[3],NULL);

	return 0;
}
void * text1(void * arg)
{
	int fp1;
	fp1 = open("/dev/key1",O_RDWR);
	while(1)
	{
		read(fp1,buf,4);
	if(*((int *)buf) == 1)
	{
		printf("key1 Press\r\n");
		key_name=1;
		msg.key_num=key_name;
		msgsnd(msg_pid,(void *)&msg,sizeof(msg.key_num),0);
	}else
	{
		memset(buf,0,1024);
	}	

	}


}
void * text2(void * arg)
{
	int fp2;
	fp2 = open("/dev/key2",O_RDWR);	
	while(1)
	{
	read(fp2,buf,4);
	if(*((int *)buf) == 2)
	{
		printf("key2 Press\r\n");
		key_name=2;
		msg.key_num=key_name;
		msgsnd(msg_pid,(void *)&msg,sizeof(msg.key_num),0);		
	}else
	{
		memset(buf,0,1024);
	}	

	}

}
void * text3(void * arg)
{
	int fp3;
	fp3 = open("/dev/key3",O_RDWR);	
	while(1)
	{
	read(fp3,buf,4);
	if(*((int *)buf) == 3)
	{
		printf("key3 Press\r\n");
		key_name=3;
		msg.key_num=key_name;
		msgsnd(msg_pid,(void *)&msg,sizeof(msg.key_num),0);		
	}else
	{
		memset(buf,0,1024);
	}		

	}

}
void * text4(void * arg)
{
	int fp4;
	fp4 = open("/dev/key4",O_RDWR);	
	while(1)
	{
	read(fp4,buf,4);
	if(*((int *)buf) == 4)
	{
		printf("key4 Press\r\n");
		key_name=4;
		msg.key_num=key_name;
		msgsnd(msg_pid,(void *)&msg,sizeof(msg.key_num),0);		
	}else
	{
		memset(buf,0,1024);
	}	

	}

}


LED驱动层:led.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/io.h>
unsigned int * led_base = NULL;
#define GPM4CON  *((volatile unsigned int *)(led_base))
#define GPM4DAT  *((volatile unsigned int *)(led_base+1))
struct miscdevice my_ops1;
struct miscdevice my_ops2;
struct miscdevice my_ops3;
struct miscdevice my_ops4;
struct file_operations my_op;
int led_open(struct inode * inode, struct file *file)
{
	int mi=MINOR(inode->i_rdev);
    printk("led_mi=%d\n",mi);
	if(mi==0)
	{
	GPM4DAT ^= (0x01<<0);
	}
	if(mi==6)
	{
	GPM4DAT ^= (0x02<<0);
	}
	if(mi==2)
	{
	GPM4DAT ^= (0x04<<0);
	}
	if(mi==3)
	{
	GPM4DAT ^= (0x08<<0);
	}
	return 0;
}
int led_close(struct inode *inode, struct file * file)
{

return 0;
}

static int __init led_start(void)
{

	my_op.owner=THIS_MODULE;
	my_op.open=led_open;
	my_op.release=led_close;
	
	my_ops1.name="led1";
	my_ops1.minor=0;
	my_ops1.fops=&my_op;
	misc_register(&my_ops1);
	
	my_ops2.name="led2";
	my_ops2.minor=6;
	my_ops2.fops=&my_op;
	misc_register(&my_ops2);
	
	my_ops3.name="led3";
	my_ops3.minor=2;
	my_ops3.fops=&my_op;
	misc_register(&my_ops3);
	
	my_ops4.name="led4";
	my_ops4.minor=3;
	my_ops4.fops=&my_op;
	misc_register(&my_ops4);

	led_base=ioremap(0x110002E0,16);
	GPM4CON &= ~(0xFFFF<<0);
	GPM4CON |= (0x1111<<0);
    return 0;
}
static void __exit led_exit(void)
{
  misc_deregister(&my_ops1);
  misc_deregister(&my_ops2);
  misc_deregister(&my_ops3);
  misc_deregister(&my_ops4);
}

module_init(led_start);
module_exit(led_exit);
MODULE_LICENSE("GPL");

LED用户层:led_app.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct message
{
	long msg_type;
	int key_num;
};
int main(void)
{
    struct message msg_recv;
    int msg_pid;
    msg_recv.msg_type=getpid();
    msg_pid=msgget(ftok("./key.c",0),IPC_CREAT|0777);
    while(1)
    {
        msgrcv(msg_pid,(void *)&msg_recv,sizeof(msg_recv.key_num),0,0);
        printf("key_num=%d\n",msg_recv.key_num);
        if(msg_recv.key_num==1)
        {
            open("/dev/led1",O_RDWR);
        }
        if(msg_recv.key_num==2)
        {
            open("/dev/led2",O_RDWR);
        }
        if(msg_recv.key_num==3)
        {
            open("/dev/led3",O_RDWR);
        }
        if(msg_recv.key_num==4)
        {
            open("/dev/led4",O_RDWR);
        }
    }
     msgctl(msg_pid,IPC_RMID,NULL);
    return 0;

}

Makefile

obj-m += key.o
obj-m += led.o
KDIR:=/home/jason/my_drive/linux-3.5

all:
	make -C $(KDIR) M=$(PWD) modules
	arm-linux-gcc key_app.c -o key_app -lpthread
	arm-linux-gcc led_app.c -o led_app 
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.markers *.order

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值