linux驱动按键控制led灯

IO端口操作

1.基本概念
机器的组成:
.处理器
.总线
.IO外设

2.IO映射及使用
1)申请IO

struct resource *request_mem_region(resource_size_t start,resource_size_t n,const char *name)
void release_mem_region(resource_size_t start,resource_size_t n)

2)映射IO

void __iomem *ioremap(unsigned long phys_addr,size_t size)
void  iounmap(void __iomem);

3)使用端口
int ioread32(void __iomem *)

iowrite32(value,void __iomem *)

实例:

driver.c

#include 
#include 
#include 
#include 
#include 
#include 		
#include 
#include "myioctl.h"

#include 
#include 

struct resource *ptr = NULL;
unsigned long *gpj2con = NULL;	//led
unsigned long *gph2con = NULL;	//key

static dev_t dev_num=0;
static struct cdev *cdev_p;

int led_open(struct inode *inode,struct file *file)
{
	printk("led kernel open func init\n");
	// led init
	int val;
	val = ioread32(gpj2con);
	val &=~(0xF<<0);
	val |=(0x1<<0);
	iowrite32(val,gpj2con);

	val = ioread32(gpj2con+1);
	val |=(0x1<<0);
	iowrite32(val,gpj2con+1);
	
	// key init
	val = ioread32(gph2con);
	val &=~(0xf<<0);
	iowrite32(val,gph2con);
	return 0;
}

int led_close(struct inode *inode,struct file *file)
{
	printk("led kernel close func init\n");
	return 0;
}


char kbuf[100];
ssize_t led_write(struct file *file, char __user *buf, size_t count, loff_t *offset)
{

	//memcpy(kbuf,buf,count);
	if(copy_from_user(kbuf,buf,count))
	{
		printk("copy data form user fail\n");
		return -EFAULT;
	}
	
	return 0;
}
//获取key值
ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
	int kbuf = (*(gph2con + 1) & (0x1));
	printk("gph2dat[0] = %d\n",kbuf);
	
	
	if(copy_to_user(buf,&kbuf,count))
	{
		printk("copy data to user fail\n");
		return -EFAULT;
	}
	return 0;
}

int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	printk("cmd=%d;arg=%d\n",cmd,arg);
	if (_IOC_NR(cmd)>=MAGIC_MAX)
		return -1;
	if (_IOC_TYPE(cmd)!=TYPE)
		return -1;
	int val;
	switch(_IOC_NR(cmd))
	{
		case 0:
		printk("led on \n");
		//*(vaddr + 1) &=~(0x1<<0);
		val = ioread32(gpj2con+1);
		val &=~(0x1<<0);
		iowrite32(val,gpj2con+1);
		break;
	case 1:
		printk("led off\n");
		//*(vaddr + 1) |=(0x1<<0);
		val = ioread32(gpj2con+1);
		val |=(0x1<<0);
		iowrite32(val,gpj2con+1);
		break;		
	case 2:
		//led on or off
		val = ioread32(gpj2con+1);
		val ^= (0x1<<0);
		iowrite32(val,gpj2con+1);
		break;
	}
	return 0;
}

struct file_operations led_fops={
	.owner=THIS_MODULE,
	.open = led_open,
	.release = led_close,
	.write 	= led_write,
	.read 	= led_read,
	.ioctl = led_ioctl,
};

int __init led_init(){
	printk("led init\n");
	int ret;
	
	ret = alloc_chrdev_region(&dev_num,0,1,"led-xx");
	if (ret < 0)
	{
		printk("chrdev num fail\n");
		return -1;
	}
	printk("dev num=%d ; major = %d ; minor = %d ;",dev_num,MAJOR(dev_num),MINOR(dev_num));
	
	cdev_p = cdev_alloc();
	cdev_init(cdev_p,&led_fops);
	ret = cdev_add( cdev_p,dev_num,1 );
	if (ret)
	{
		printk("cdev add fail\n");
		return -1;
	}
	//申请io端口,请求分配指定的I/O内存资源。led-xx可以改?
	ptr = request_mem_region(0xe0200280,0x1000,"led-xx");
	if (ptr == NULL)
	{
		printk("request_mem_region fail\n");
		return -1;
	}
	//映射io
	gpj2con = (unsigned long *)ioremap(0xe0200280,0x1000);
	if (gpj2con == NULL)
	{
		printk("ioremap fail\n");
		return -1;
	}
	//这里不用申请io?
	gph2con = (unsigned long *)ioremap(0xe0200c40,0x1000);
	if (gph2con == NULL)
	{
		printk("ioremap fail\n");
		return -1;
	}
	return 0;
}

void __exit led_exit(){

	iounmap(gpj2con);
	iounmap(gph2con);
	release_mem_region(0xe0200280,0x1000);
	release_mem_region(0xe0200c40,0x1000);

	cdev_del(cdev_p);
	unregister_chrdev_region(dev_num,1);

	printk("led exit\n");
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("LEDxx");
MODULE_AUTHOR("XX");
MODULE_DESCRIPTION("xx test");

myioctl.h

#define LED_NUM1	1	
#define LED_NUM2	2
#define STEP_MOTO   3

#define MOTO_ON 	0
#define MOTO_OFF	1


#define TYPE	'K'
#define MAGIC_MAX	3
#define LED_ON 		_IO(TYPE,0)
#define LED_OFF 	_IO(TYPE,1)
#define LED_EOR		_IO(TYPE,2)
app.c

#include 
#include 
#include 
#include 
#include 

#include "myioctl.h"
int key_val;

int main(int argc,char **argv)
{
	int fd = open("/dev/xxled",O_RDWR);
	if(fd < 0)
	{
		printf("open fail\n");
		return -1;
	}

	while(1)
	{	//循环read读取key的值
		read(fd,&key_val,4);//读4个字节,32位
		if(key_val == 0)
		{
			// 按下去抖
			do{
				usleep(100000);
				read(fd,&key_val,4);
			}while(key_val == 0);
		//读取到按下就ioctl修改led灯状态
			ioctl(fd,LED_EOR);
		}
		//300毫秒读一次
		usleep(300000);
	}

	close(fd);
	return 0;
}

makefile


obj-m += led.o

KERNEL_DIR := /usr/mkdrv/src/android-kernel-samsung-dev

all:
	make modules -C $(KERNEL_DIR) M=`pwd`
	arm-linux-gcc app.c -o app
	cp led.ko app /nfs  
	make clean

clean:
	make modules clean -C $(KERNEL_DIR) M=`pwd` 




你可能感兴趣的:(嵌入式)