#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
typedef unsigned long Uint32;
//寄存器定义
volatile unsigned long *gpiog_con=NULL;
volatile unsigned long *gpiog_data=NULL;
volatile unsigned long *gpiof_con=NULL;
volatile unsigned long *gpiof_data=NULL;
int major;
static struct class* drv_keyled_class;
static struct class_device* drv_keyled_class_device;
/***驱动关键函数实现****/
/*
函数名:drv_keyled_open
功能:配置引脚功能
*/
int drv_keyled_open(struct inode *inode, struct file *file)
{
char key_dat=1;
printk("drv_keyled_open2\n");
//GPF4.5.6
*gpiof_con |= (1<<2*4) | (1<<2*5) | (1<<2*6) ; //输出 led
*gpiof_data &= ((~(1<<4)) & (~(1<<5)) & (~(0<<6))); //2个亮
//GPG3,GPP0,GPP2
*gpiog_con |= (0x3<<2*11) ; //输入 key ((0x3<<2*3)) |
return 0;
}
/*
函数名:drv_keyled_write
功能:控制led亮灭,实现反转
*/
static ssize_t drv_keyled_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
unsigned char key_data[2]={1,1};;
Uint32 data=*gpiof_data;
//测试:读取用户传入的按键值
copy_from_user(key_data, buf, count);
printk("kernel:the key is:%d , %d\n",key_data[0] ,key_data[1] ); //检验用户空间传输的按键值
//反转led
*gpiof_data |= (1<<4) | (1<<5) |(1<<6);
*gpiof_data &= ~(data & ((1<<4) | (1<<5) |(1<<6))); //反转指定位电平同时其他的不影响
return 0;
}
/*
函数名:drv_keyled_read
功能:读key电平
*/
static ssize_t drv_keyled_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
unsigned char key_data[2]={1,1};
unsigned char keybuf=0;
if(size != sizeof(key_data))//用户空间(应用程序)要读取的字节与内核空间存的字节数一致
{
printk("err:size");
return -EINVAL;
}
//把读取的按键值发给用户空间(应用端)
key_data[0] = (*gpiof_data & (1<<0)) ? 1 : 0;
key_data[1] = (*gpiog_data & (1<<3)) ? 1 : 0;
if( key_data[0] == 0)
{
printk("key1 press \n");
while(!keybuf)//按下弹出
{
keybuf= (*gpiof_data & (1<<0)) ? 1 : 0;
}
}
if( key_data[1] == 0)
{
printk("key2 press \n");
while(!keybuf)//按下弹出
{
keybuf= (*gpiog_data & (1<<3)) ? 1 : 0;
}
}
copy_to_user(buf, key_data, sizeof(key_data));//copy_to_user(用户空间,内核空间,字节数)
return sizeof(key_data);
}
//关键函数绑定
static struct file_operations drv_key_fops=
{
.owner = THIS_MODULE,
.write = drv_keyled_write,
.read = drv_keyled_read,
.open = drv_keyled_open,
};
/*
函数名:drv_keyled_init
功能:初始化模块功能(insmod装载时调用)
*/
static int drv_keyled_init(void)
{
//注册主设备号,由fops结构体告诉内核绑定的函数
major = register_chrdev(0, "drv_keyled", &drv_key_fops);
//创建类
drv_keyled_class = class_create(THIS_MODULE, "drv_keyled");
//创建类设备
drv_keyled_class_device = class_device_create(drv_keyled_class, NULL, MKDEV(major, 0), NULL, "keyled");// "/dev/keyled"
//虚拟地址VA映射
gpiof_con = (unsigned long*)ioremap(0x56000050, 12); //映射物理地址的起始地址与长度,返回虚拟地址
gpiof_data = gpiof_con+1;//地址在类型长度上加1(即+4地址)
gpiog_con = (unsigned long*)ioremap(0x56000060, 12); //映射物理地址的起始地址与长度,返回虚拟地址
gpiog_data = gpiog_con+1;
return 0;
}
/*
函数名:drv_keyled_exit
功能:卸载模块功能(rmmod卸载时调用)
*/
static void drv_keyled_exit(void)
{
unregister_chrdev(major, "drv_keyled");
class_device_unregister(drv_keyled_class_device);
class_destroy(drv_keyled_class);
iounmap(gpiof_con);
iounmap(gpiog_con);
}
/**绑定驱动中关键实现函数**/
//初始化、卸载函数绑定(宏)
module_init(drv_keyled_init);
module_exit(drv_keyled_exit);
//其他,声明驱动
MODULE_LICENSE("GPL");