平台设备+中断+定时综合例子

本文提供了一个关于按键点亮LED灯的实例,旨在学习和巩固Linux驱动知识。通过使用平台总线方式注册设备和驱动,该实例展示了如何在修改驱动时不需修改核心驱动代码,体现分层分类思想。实例涉及中断、定时器、轮询方式及字符设备相关知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是一个关于按键点亮led灯的综合例子,没什么用处,但是综合度还是挺大的,主要是用来学习和巩固linux驱动的只是,适合学习linux驱动初级者,该程序以平台总线的方式注册led device 和 led driver, 当需要修改一个驱动的时候,之需要修改 led device 就可以,无需修改 led driver, 即 体现了平台设备总线分层分类的思想,该例子除了设计平台设备知识外,还设计中断 , 定时器, 轮询方式等和一些字符设备相关的知识,请阅读,如需修改的地方,请网友指出,互相学习。

LCplatform.h

#ifndef LCPLATFORM_H
#define LCPLATFORM_H

#define PLATFORM_NAME "LCPlatform"
#define PLATFORM_MAJOR 0
#define PLATFORM_MINOR 0
#define MASK 0

#define GPBCON	0x56000010
#define GPBDAT  0x56000014
#define GPGCON  0x56000060
#define GPGDAT  0x56000064
#define GPGUP   0x56000068
#define GPG0    (1<<0)
#define GPG3    (1<<3)
#define GPG5    (1<<5)
#define GPG6    (1<<6)
#define GPG7    (1<<7)
#define GPG11   (1<<11)


#define IRQNUM	0
#define K1      GPG0
#define K2      GPG3
#define K3      GPG5
#define K4      GPG6
#define K5      GPG7
#define K6      GPG11

#define LED1    5
#define LED2    6
#define LED3    7
#define LED4    8

enum
{
	key_up = 0,
	key_down ,
};

#endif



led_devie.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "LCplatform.h"

static struct resource LCPlatform_resource[] = 
{
	[0] = {
		.start = GPGCON,
		.end   = GPGCON + 8 - 1,
		.flags = IORESOURCE_MEM,
	},
	
	[1] = {
		.start = GPBCON,
		.end   = GPBCON + 8 - 1,
		.flags = IORESOURCE_MEM,
	}, 
	
	[2] = {
		.start = IRQNUM,
		.end   = IRQNUM,
		.flags = IORESOURCE_IRQ,
	},
};

static void LCRelease(struct inode * inode,struct file * file)
{
	printk("%s: release platform device\n", __func__);
}

static struct platform_device LCPlatform_device = 
{
	.resource     = LCPlatform_resource,
	.num_resources = ARRAY_SIZE(LCPlatform_resource),
	.id           = -1,
	.name         = PLATFORM_NAME,
	.dev = {
		.release = LCRelease,
	}
};

static int LCPlatform_init_module(void)
{
	int ret;
	ret = platform_device_register(&LCPlatform_device);
	if(ret<0)
	{	
		printk("%s: register platform device fail\n",__func__);
		return ret;
	}
	printk("%s: register platform device success\n",__func__);
	return 0;
}

static void LCPlatform_exit_module(void)
{
	platform_device_unregister(&LCPlatform_device);
}

module_init(LCPlatform_init_module);
module_exit(LCPlatform_exit_module);
MODULE_LICENSE("GPL");

led_driver.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <linux/kdev_t.h>  
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <mach/regs-gpio.h>
#include <linux/poll.h>
#include "LCplatform.h"


#ifdef SHOW_LOG
	#define print_log(args, ...) printk(args, ##__VA_ARGS__)
#endif

unsigned int *LEDDRESS;
static struct class *LCPlatform_class;
static unsigned long timer_arg = 1;
static struct timer_list LCPlatform_timer;
static volatile unsigned long * gpio_b_con;
static volatile unsigned long * gpio_b_dat;
static volatile unsigned long * gpio_g_con;
static volatile unsigned long * gpio_g_dat;

static unsigned char keyStatus = key_up;
static unsigned char isPressed = 0;
static unsigned char flag_irq = 0;
static DECLARE_MUTEX(button_lock);
static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue);


void LCPlatform_do_timer(unsigned long data)
{
	if( !(*gpio_g_dat & 0x01))
		keyStatus = key_down;
	else
		keyStatus = key_up;
	print_log("%s: keyStatus = %d", __FUNCTION__, keyStatus);
	if(keyStatus)
	{  /* exchange to turn on and off*/
		if(!(*gpio_b_dat & ((1<<LED1) | (1<<LED2) | (1<<LED3) | (1<<LED4))))
			*gpio_b_dat |=  (1<<LED1) | (1<<LED2) | (1<<LED3) | (1<<LED4); // all light off
		else
			*gpio_b_dat &= ~((1<<LED1) | (1<<LED2) | (1<<LED3) | (1<<LED4)); //all light on

		isPressed = 1;
		wake_up_interruptible(&button_wait_queue);
	}
	else
		*gpio_b_dat |=  (1<<LED1) | (1<<LED2) | (1<<LED3) | (1<<LED4); // all light off

	flag_irq = 0;
}

static irqreturn_t  LCPlatform_Handle_irq(int irqNO, struct resource *LCplatform_resource)
{
	if(!flag_irq)
	{
		LCPlatform_timer.expires  = jiffies + HZ/10; //100ms
	   LCPlatform_timer.function = LCPlatform_do_timer;
		add_timer(&LCPlatform_timer);
		flag_irq = 1;
	}
	return  IRQ_RETVAL(IRQ_HANDLED);
}

static int LCPlatform_open(struct inode* inode, struct file *file)
{
	int ret;
	if(file->f_flags & O_NONBLOCK)
	{
		if(down_trylock(&button_lock))
			return -EBUSY;		
	}
	else
	{
		down(&button_lock);
	}
	
	ret = request_irq(IRQ_EINT8,LCPlatform_Handle_irq,IRQ_TYPE_EDGE_FALLING,"S3C_IRQTYPE_EINT",NULL);
	if(ret)
	{
		print_log("%s: request irq fail\n",__FUNCTION__);
		return -EIO;
	}
	init_timer(&LCPlatform_timer);
	return ret;
}

static int LCPlatform_release(struct inode* inode, struct file *file)
{
	int ret = 0;
	free_irq(IRQ_EINT8, NULL);
	ret = del_timer(&LCPlatform_timer);
	up(&button_lock);
	return ret;
}

static int LCPlatform_read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
{
	int ret;
	if(file->f_flags & O_NONBLOCK)
	{
		if(!isPressed)
			return -EAGAIN;
	}		
	print_log("%s: do read\n",__FUNCTION__);
	if(bytes> sizeof(char))
		bytes = sizeof(char);
	wait_event_interruptible(button_wait_queue,isPressed);
	ret = copy_to_user(userbuf, &isPressed, sizeof(char));
	if(ret)
	{
		print_log("%s: copy to user fail\n", __FUNCTION__);
		return -EFAULT;
	}
	isPressed = 0;
	return ret;
}

unsigned int LCPlatform_poll(struct file *file, struct poll_table_struct *poll_table)
{
	unsigned int mask;
	poll_wait(file, &button_wait_queue, poll_table);
	if(isPressed)
	{
		mask |= POLLIN | POLLRDNORM;
	}
	return mask;
}

static struct file_operations LCPlatform_ops = 
{
	.open    = LCPlatform_open,
	.release = LCPlatform_release,
	.read    = LCPlatform_read,
	.poll    = LCPlatform_poll,
	.owner   = THIS_MODULE	
};

/* config gpio  */
static int LCPlatform_set_gpio(struct platform_device *LCPlatform_device)
{
	struct resource *LCplatform_resource;
	unsigned char key;

	/* config key */
	LCplatform_resource = platform_get_resource(LCPlatform_device, IORESOURCE_MEM, 0);
	if(!LCplatform_resource)
	{
		print_log("%s: get resource IORESOURCE_MEM fail\n", __FUNCTION__);
		return -EFAULT;
	}
	gpio_g_con = (volatile unsigned long *)ioremap(LCplatform_resource->start,LCplatform_resource->end - LCplatform_resource->start + 1);
	gpio_g_dat = gpio_g_con + 1;

	LCplatform_resource = platform_get_resource(LCPlatform_device, IORESOURCE_IRQ, 0);
	if(!LCplatform_resource)
	{
		print_log("%s: get resource IORESOURCE_IRQ fail\n", __FUNCTION__);
		goto fail;
	}
	key = LCplatform_resource->start;
	/* config EINT irq*/
	*gpio_g_con |= (0x02 << key); 

	/* config led */
	LCplatform_resource = platform_get_resource(LCPlatform_device, IORESOURCE_MEM, 1);
	if(!LCplatform_resource)
	{
		print_log("%s: get resource IORESOURCE_IRQ fail\n", __FUNCTION__);
		goto fail;
	}
	gpio_b_con = (volatile unsigned long *)ioremap(LCplatform_resource->start,LCplatform_resource->end - LCplatform_resource->start + 1);
	gpio_b_dat = gpio_b_con + 1;

	*gpio_b_con |= (1<<LED1*2) | (1<<LED2*2) | (1<<LED3*2) | (1<<LED4*2); //config out
	return 0;
	
fail:
	iounmap(gpio_g_con);
    return 	EFAULT;
	

}

int LCPlatform_probe(struct platform_device *LCPlatform_device)
{
	int ret = 0;
	int major;
	
	ret = LCPlatform_set_gpio(LCPlatform_device);
	
	if(ret)
	{
		print_log("%s: set gpio fail\n",__FUNCTION__);
		return EAGAIN;
	}
	major = register_chrdev(0, PLATFORM_NAME, &LCPlatform_ops);

	if(!major)
	{
		print_log("%s: use defalut major\n", __FUNCTION__);
		major = PLATFORM_MAJOR;
		ret = register_chrdev(major,PLATFORM_NAME,&LCPlatform_ops);
		if(!ret)
		{
			print_log("%s: register char device fail\n",__FUNCTION__);
			return ret;
		}
	}
	
	LCPlatform_class = class_create(THIS_MODULE, "LCPlatform");
	if(!LCPlatform_class)
	{
		print_log("%s: class create fial\n", __FUNCTION__);
		unregister_chrdev(major, PLATFORM_NAME);
	}
	if(!device_create(LCPlatform_class, NULL, MKDEV(major,PLATFORM_MINOR),NULL,PLATFORM_NAME))
	{
		print_log("%s: device create fail\n", __FUNCTION__);
		goto fail_1;
	}
	return ret;
	
fail_1:
	class_destroy(LCPlatform_class);
	unregister_chrdev(major, PLATFORM_NAME);
	return -EAGAIN;
}

static struct platform_driver LCPlatform_driver = {
	.probe     = LCPlatform_probe,
	.driver    = {
		.name  = PLATFORM_NAME,
		.owner = THIS_MODULE,
	}
};

static int LCPlatform_init_module()
{
	int ret;
	ret = platform_driver_register(&LCPlatform_driver);
	if(ret<0)
	{
		print_log("%s: init platform module fail\n",__func__);
		return ret;
	}
	print_log("%s: init platform module success\n",__func__);
	return ret;
}

static void LCPlatform_exit_module()
{
	device_destroy(LCPlatform_class, MKDEV(PLATFORM_MAJOR,PLATFORM_MINOR));
	class_destroy(LCPlatform_class);
	platform_driver_unregister(&LCPlatform_driver);
	del_timer(&LCPlatform_timer);
}

module_init(LCPlatform_init_module);
module_exit(LCPlatform_exit_module);
MODULE_AUTHOR("junzhang");
MODULE_LICENSE("GPL");

Makefile

KDIR = /home/share/linux-2.6/linux-2.6.32.2/

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

obj-m += platform_device.o
obj-m += platform_driver.o

EXTRA_CFLAGS += -DSHOW_LOG
#CFLAGS_platform_device.o += -DSHOW_LOG
clean:
	rm *.o platform_device.mod.c platform_driver.mod.c modules.order Module.symvers


app

test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#define filePath "/dev/LCPlatform"

int main()
{
	int fd;
	int ret;
	unsigned char data;
	fd_set FdTable;
	struct timeval pollTimer;
	fd = open(filePath, O_RDWR, S_IRUSR | S_IWUSR);
	
	if(fd<0)
	{
		printf("%s: open %s fail", __FUNCTION__, filePath);
		return fd;
	}
	printf("open success\n");
	
	while(1)
	{
		FD_ZERO(&FdTable);
		FD_SET(fd, &FdTable);
		pollTimer.tv_sec = 5;
		pollTimer.tv_usec = 0;
		ret = select(fd+1, &FdTable, NULL, NULL, &pollTimer);
		if(FD_ISSET(fd, &FdTable))
		{
			ret = read(fd, &data, sizeof(char));
			if(ret != sizeof(char))
				printf("%s: read error \n", __FUNCTION__);
			printf("%s: data = %d", __FUNCTION__, data);
		}
		else
			printf("%s: poll time out\n", __FUNCTION__);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值