Linux驱动之按键读取(基于寄存器操作)

概述

其实就是在上一章“LED驱动”中的file_operations中添加read系统接口,仅此而已。

基础知识

(一) copy_from_user、copy_to_user使用
函数包含于<asm/uaccess.h>头文件中,实现内核空间和用户空间之间的数据拷贝功能。

/static inline int copy_from_user(void *to, const void __user volatile *from,unsigned long n)
/*拷贝from用户空间,to内核空间,拷贝长度n字节*/
static inline int copy_to_user(void __user volatile *to, const void *from,unsigned long n) 
/*拷贝to用户空间,from内核空间,拷贝长度n字节*/   

驱动代码

#include <linux/fs.h>        /*包含file_operation结构体*/
#include <linux/init.h>      /* 包含module_init module_exit */
#include <linux/module.h>    /* 包含LICENSE的宏 */
#include <linux/miscdevice.h>/*包含miscdevice结构体*/
#include <linux/io.h>        /*包含ioremap等操作函数*/
#include <linux/kernel.h>    /*包含printk等操作函数*/
#include <asm/uaccess.h>     /*包含copy_to_user操作函数*/

/**************宏定义***************/

#define PIO_PER		(*(volatile unsigned long *)(virt_addr +0x0000))/*虚拟寄存器地址*/
#define PIO_MDDR	(*(volatile unsigned long *)(virt_addr +0x0054))
#define PIO_OWDR	(*(volatile unsigned long *)(virt_addr +0x00A4))
#define PIO_PDSR	(*(volatile unsigned long *)(virt_addr +0x003C))
#define PIO_ODR     (*(volatile unsigned long *)(virt_addr +0x0014))

#define 	KEY1		1 << 0
#define 	KEY2		1 << 2
#define 	KEY3		1 << 4
#define 	KEY4		1 << 6
/**************内部变量***************/
unsigned long virt_addr;

/* 定义一个打开设备的,open函数 */
static int key_open(struct inode *inode,struct file *file)
{
	return 0;
}

/* 定义一个打开设备的,read函数 */
ssize_t key_read(struct file *file, char __user *array, size_t size, loff_t *ppos)
{
	unsigned int readData;
	char buf[4];
	int res;	
	readData = PIO_PDSR;
	buf[0] = (char)(readData>>0)&0x01;
	buf[1] = (char)(readData>>2)&0x01;
	buf[2] = (char)(readData>>4)&0x01;
	buf[3] = (char)(readData>>6)&0x01;
	printk("%d=%d=%d=%d\r\n",buf[0],buf[1],buf[2],buf[3]);
	res = copy_to_user(array,buf,4);
	if(!res)
	return 4;
	else 
	return -1;
}

/*字符设备驱动程序就是为具体硬件的file_operations结构编写各个函数*/
static const struct file_operations key_ctl={
         .owner          = THIS_MODULE,
         .open           = key_open,
		 .read           = key_read,
};

/*杂项设备,主设备号为10的字符设备,相对普通字符设备,使用更简单*/
static struct miscdevice key_miscdev = {
         .minor          = 255,
         .name           = "key_read",
         .fops           = &key_ctl,
};

static int __init key_init(void)
{
	char res;
	/*注册杂项设备驱动*/
	res = misc_register(&key_miscdev);
	printk(KERN_ALERT"key_init %d\n",res);

	/*通过物理地址,得到寄存器的虚拟地址*/
	virt_addr =(volatile unsigned long )ioremap(0Xfffff600,0x200); 
	
	/*对物理寄存器操作,IO口输入使能*/
	PIO_PER  |= KEY1 | KEY2 | KEY3 | KEY4;//IO使能
	PIO_MDDR |= KEY1 | KEY2 | KEY3 | KEY4;//取消复用功能
	PIO_ODR  |= KEY1 | KEY2 | KEY3 | KEY4;//设置为输入
	return res;
}

static void __exit key_exit(void)
{
	/*释放杂项设备*/
	misc_deregister(&key_miscdev);
	/*取消虚拟地址映射*/
	iounmap((unsigned long *)virt_addr);
	printk(KERN_ALERT"key_exit\r\n");
}

/*驱动模块的加载和卸载入口*/
module_init(key_init);
module_exit(key_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("boyee");
MODULE_DESCRIPTION("read key");

简单makefile

KERNEL_DIR:=/home/boyee/at91/linux-at91-V3.18.0-git
CROSS=arm-linux- 
obj-m +=keyRead.o
all:
	make -C $(KERNEL_DIR) M=`pwd` modules
clean:
	rm -rf *.o *.ko

用户测试程序

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

int main(int argc, char *argv[])
{
	char *keys = "/dev/key_read";
	int fd;
	char buf[5];
	if((fd = open(keys,O_RDWR))<0)
	{
		printf("key open err\r\n");
		return -1;
	}
	while(1)
	{
		read(fd,buf,4);
		printf("%d-%d-%d-%d\r\n",buf[0],buf[1],buf[2],buf[3]);
		sleep(1);
	}
	close(fd);
	return 0;
}

测试结果

1.编译生成xxx.ko文件和测试程序
在这里插入图片描述
2.上传开发板insmod驱动,testAPP运行测试
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值