update
This commit is contained in:
parent
0f00130af8
commit
86bfc171c1
22
code/App/interrupt_dev/key_cdev.c
Normal file
22
code/App/interrupt_dev/key_cdev.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
unsigned int keyval;
|
||||||
|
int fd = 0;
|
||||||
|
/* 打开驱动文件 */
|
||||||
|
fd = open(argv[1], O_RDWR);
|
||||||
|
if (fd<0) printf("can't open %s file\n",argv[1]);
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
read(fd, &keyval,sizeof(keyval));
|
||||||
|
printf("key_value = %d\n",keyval);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
38
code/App/led_dev/led_dev.c
Normal file
38
code/App/led_dev/led_dev.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char* filename=NULL;
|
||||||
|
int val;
|
||||||
|
filename = argv[1];
|
||||||
|
fd = open(filename, O_RDWR);//打开dev/设备文件
|
||||||
|
if (fd < 0)//小于0说明没有成功
|
||||||
|
{
|
||||||
|
printf("error, can't open %s\n", filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(argc !=3)
|
||||||
|
{
|
||||||
|
printf(argv[1]);//打印用法
|
||||||
|
}
|
||||||
|
if(!strcmp(argv[2], "on")) //如果输入等于on,则LED亮
|
||||||
|
val = 0;
|
||||||
|
else if(!strcmp(argv[2], "off")) //如果输入等于off,则LED灭
|
||||||
|
val = 1;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
write(fd, &val, 4);//操作LED
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
printf("usage: ./led_dev.exe [device] [on/off]\n");
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
37
code/App/mykeypad/mykeypad.c
Normal file
37
code/App/mykeypad/mykeypad.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define CHECK_POINT
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int fd = open(argv[1],O_RDONLY);
|
||||||
|
#ifdef CHECK_POINT
|
||||||
|
printf("fd = %d\n",fd);
|
||||||
|
#endif
|
||||||
|
struct input_event t;
|
||||||
|
printf("size of t = %d\n",sizeof(t));
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
printf("while -\n");
|
||||||
|
int len = read(fd, &t, sizeof(t));
|
||||||
|
if(len == sizeof(t))
|
||||||
|
{
|
||||||
|
printf("read over\n");
|
||||||
|
if(t.type==EV_KEY)
|
||||||
|
{
|
||||||
|
printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released");
|
||||||
|
if(t.code == KEY_ESC)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef CHECK_POINT
|
||||||
|
printf("len = %d\n",len);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
11
code/Driver/interrupt/Makefile
Normal file
11
code/Driver/interrupt/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||||
|
rm -rf modules.order *.ko
|
||||||
|
|
||||||
|
obj-m +=key_dev_platform.o
|
||||||
|
|
||||||
150
code/Driver/interrupt/key_dev.c
Normal file
150
code/Driver/interrupt/key_dev.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有iomap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的处理函数
|
||||||
|
#include <linux/irq.h> //含有IRQ_HANDLED和IRQ_TYPE_EDGE_RISING
|
||||||
|
#include <linux/interrupt.h> //含有request_irq、free_irq函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static dev_t btn_cdev_num; //定义一个设备号
|
||||||
|
static struct cdev *btn_cdev; //定义一个设备管理结构体指针
|
||||||
|
static struct class *btn_class; //定义一个设备类
|
||||||
|
static struct device *btn; //定义一个设备
|
||||||
|
|
||||||
|
#define KEYADC_BASE (0x01C22800)
|
||||||
|
#define KEYADC_CTRL_REG (KEYADC_BASE+0x00)
|
||||||
|
#define KEYADC_INTC_REG (KEYADC_BASE+0x04)
|
||||||
|
#define KEYADC_INTS_REG (KEYADC_BASE+0x08)
|
||||||
|
#define KEYADC_DATA_REG (KEYADC_BASE+0x0C)
|
||||||
|
|
||||||
|
ssize_t volatile *keyadc_ctrl;
|
||||||
|
ssize_t volatile *keyadc_intc;
|
||||||
|
ssize_t volatile *keyadc_ints;
|
||||||
|
ssize_t volatile *keyadc_data;
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int ev_press; //一个全局变量,记录中断事件状态
|
||||||
|
DECLARE_WAIT_QUEUE_HEAD(btn_waitq);//注册一个等待队列button_waitq,用宏来申明一个全局变量
|
||||||
|
static unsigned int key_value = 0; //定义一个变量保存按键值
|
||||||
|
|
||||||
|
static irqreturn_t btn_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
wake_up_interruptible(&btn_waitq); /* 唤醒休眠的进程,即调用read函数的进程 */
|
||||||
|
ev_press = 1;
|
||||||
|
*keyadc_ints |= ((1<<0)|(1<<1) | (1<<2) |(1<<3)|(1<<4));
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btn_cdev_open (struct inode * inode, struct file * file)
|
||||||
|
{
|
||||||
|
*keyadc_intc |= ((1<<0)|(1<<1)|(1<<4));
|
||||||
|
*keyadc_ctrl |= (1<<7);
|
||||||
|
*keyadc_ctrl &= ~(0xf<<8);
|
||||||
|
*keyadc_ctrl |= (1<<0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btn_cdev_close(struct inode * inode, struct file * file)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t btn_cdev_read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned int adc_value;
|
||||||
|
adc_value = *(keyadc_data);
|
||||||
|
//将当前进程放入等待队列button_waitq中,并且释放CPU进入睡眠状态
|
||||||
|
wait_event_interruptible(btn_waitq, ev_press!=0);
|
||||||
|
ret = copy_to_user(userbuf, &adc_value, 4);//将取得的按键值传给上层应用
|
||||||
|
|
||||||
|
printk(KERN_WARNING"key adc = %d\n",(adc_value&(0x3f)));
|
||||||
|
printk(KERN_WARNING"key statue = 0x%x\n",*(keyadc_ints));
|
||||||
|
ev_press = 0;//按键已经处理可以继续睡眠
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
printk("copy error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_operations btn_cdev_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = btn_cdev_open,
|
||||||
|
.read = btn_cdev_read,
|
||||||
|
.release = btn_cdev_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int btn_cdev_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
btn_cdev = cdev_alloc(); //动态申请一个设备结构体
|
||||||
|
if(btn_cdev == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"cdev_alloc failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = alloc_chrdev_region(&btn_cdev_num,0,1,"button"); //动态申请一个设备号
|
||||||
|
if(ret !=0)
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"alloc_chrdev_region failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
btn_cdev->owner = THIS_MODULE; //初始化设备管理结构体的owner为THIS_MODULE
|
||||||
|
btn_cdev->ops = &btn_cdev_ops; //初始化设备操作函数指针为led_ops函数
|
||||||
|
cdev_add(btn_cdev,btn_cdev_num,1); //将设备添加到内核中
|
||||||
|
btn_class = class_create(THIS_MODULE, "button"); //创建一个名为led_class的类
|
||||||
|
if(btn_class == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"btn_class failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
btn = device_create(btn_class,NULL,btn_cdev_num,NULL,"button0"); //创建一个设备名为led0
|
||||||
|
if(IS_ERR(btn))
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"device_create failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyadc_ctrl = ioremap(KEYADC_CTRL_REG, 4);//重映射
|
||||||
|
keyadc_intc = ioremap(KEYADC_INTC_REG, 4);//重映射
|
||||||
|
keyadc_ints = ioremap(KEYADC_INTS_REG, 4);//重映射
|
||||||
|
keyadc_data = ioremap(KEYADC_DATA_REG, 4);//重映射
|
||||||
|
ret = request_any_context_irq(35, btn_irq, 0 , "btn",(void*)&key_value);
|
||||||
|
if(ret) //返回不为0,表示申请失败
|
||||||
|
{
|
||||||
|
printk("request irq failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void btn_cdev_exit(void)
|
||||||
|
{
|
||||||
|
cdev_del(btn_cdev); //从内核中删除设备管理结构体
|
||||||
|
unregister_chrdev_region(btn_cdev_num,1); //注销设备号
|
||||||
|
device_destroy(btn_class,btn_cdev_num); //删除设备节点
|
||||||
|
class_destroy(btn_class); //删除设备类
|
||||||
|
|
||||||
|
iounmap(keyadc_ctrl);//取消重映射
|
||||||
|
iounmap(keyadc_intc);//取消重映射
|
||||||
|
iounmap(keyadc_ints);//取消重映射
|
||||||
|
iounmap(keyadc_data);//取消重映射
|
||||||
|
free_irq(35,(void*)&key_value);//释放中断
|
||||||
|
printk("unregister btn_cdev\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module_init(btn_cdev_init);
|
||||||
|
module_exit(btn_cdev_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
174
code/Driver/interrupt/key_dev_platform.c
Normal file
174
code/Driver/interrupt/key_dev_platform.c
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的设备函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/platform_device.h> //包含platform函数
|
||||||
|
#include <linux/of.h> //包含设备树相关函数
|
||||||
|
#include <linux/irq.h> //含有IRQ_HANDLED和IRQ_TYPE_EDGE_RISING
|
||||||
|
#include <linux/interrupt.h> //含有request_irq、free_irq函数
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static dev_t btn_cdev_num; //定义一个设备号
|
||||||
|
static struct cdev *btn_cdev; //定义一个设备管理结构体指针
|
||||||
|
static struct class *btn_class; //定义一个设备类
|
||||||
|
static struct device *btn; //定义一个设备
|
||||||
|
|
||||||
|
ssize_t volatile *keyadc_ctrl;
|
||||||
|
ssize_t volatile *keyadc_intc;
|
||||||
|
ssize_t volatile *keyadc_ints;
|
||||||
|
ssize_t volatile *keyadc_data;
|
||||||
|
|
||||||
|
static unsigned int ev_press; //一个全局变量,记录中断事件状态
|
||||||
|
DECLARE_WAIT_QUEUE_HEAD(btn_waitq);//注册一个等待队列button_waitq,用宏来申明一个全局变量
|
||||||
|
static unsigned int key_value = 0; //定义一个变量保存按键值
|
||||||
|
|
||||||
|
|
||||||
|
static irqreturn_t btn_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
ssize_t ints_clr = *keyadc_ints;
|
||||||
|
ints_clr = *keyadc_ints;
|
||||||
|
wake_up_interruptible(&btn_waitq); /* 唤醒休眠的进程,即调用read函数的进程 */
|
||||||
|
ev_press = 1;
|
||||||
|
*keyadc_ints |= ints_clr;
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btn_cdev_open (struct inode * inode, struct file * file)
|
||||||
|
{
|
||||||
|
*keyadc_ctrl&=0;
|
||||||
|
*keyadc_ctrl |= (2<<24) | (1<<8) | (1<<6);
|
||||||
|
*keyadc_intc |= (1<<4) | (1<<1);
|
||||||
|
*keyadc_ctrl |= (1<<0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btn_cdev_close(struct inode * inode, struct file * file)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t btn_cdev_read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned int adc_value;
|
||||||
|
adc_value = *(keyadc_data);
|
||||||
|
//将当前进程放入等待队列button_waitq中,并且释放CPU进入睡眠状态
|
||||||
|
wait_event_interruptible(btn_waitq, ev_press!=0);
|
||||||
|
ret = copy_to_user(userbuf, &adc_value, 4);//将取得的按键值传给上层应用
|
||||||
|
|
||||||
|
printk(KERN_WARNING"key adc = %d\n",(adc_value&(0x3f)));
|
||||||
|
printk(KERN_WARNING"key statue = 0x%x\n",*(keyadc_ints));
|
||||||
|
ev_press = 0;//按键已经处理可以继续睡眠
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
printk("copy error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_operations btn_cdev_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = btn_cdev_open,
|
||||||
|
.read = btn_cdev_read,
|
||||||
|
.release = btn_cdev_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int btn_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
btn_cdev = cdev_alloc(); //动态申请一个设备结构体
|
||||||
|
if(btn_cdev == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"cdev_alloc failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = alloc_chrdev_region(&btn_cdev_num,0,1,"button"); //动态申请一个设备号
|
||||||
|
if(ret !=0)
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"alloc_chrdev_region failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
btn_cdev->owner = THIS_MODULE; //初始化设备管理结构体的owner为THIS_MODULE
|
||||||
|
btn_cdev->ops = &btn_cdev_ops; //初始化设备操作函数指针为led_ops函数
|
||||||
|
cdev_add(btn_cdev,btn_cdev_num,1); //将设备添加到内核中
|
||||||
|
btn_class = class_create(THIS_MODULE, "button"); //创建一个名为led_class的类
|
||||||
|
if(btn_class == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"btn_class failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
btn = device_create(btn_class,NULL,btn_cdev_num,NULL,"button0"); //创建一个设备名为led0
|
||||||
|
if(IS_ERR(btn))
|
||||||
|
{
|
||||||
|
printk(KERN_WARNING"device_create failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的LRADC_CTRL
|
||||||
|
keyadc_ctrl = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的LRADC_INTC
|
||||||
|
keyadc_intc = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的LRADC_INTS
|
||||||
|
keyadc_ints = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的LRADC_DATA
|
||||||
|
keyadc_data = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
|
||||||
|
ret = devm_request_irq(&pdev->dev, platform_get_irq(pdev, 0), btn_irq, 0, "mykey", (void*)&key_value);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btn_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
iounmap(keyadc_ctrl); //取消LRADC_CTRL映射
|
||||||
|
iounmap(keyadc_intc); //取消LRADC_INTC映射
|
||||||
|
iounmap(keyadc_ints); //取消LRADC_INTS映射
|
||||||
|
iounmap(keyadc_data); //取消LRADC_DATA映射
|
||||||
|
cdev_del(btn_cdev); //从内核中删除设备管理结构体
|
||||||
|
|
||||||
|
unregister_chrdev_region(btn_cdev_num,1); //注销设备号
|
||||||
|
device_destroy(btn_class,btn_cdev_num); //删除设备节点
|
||||||
|
class_destroy(btn_class); //删除设备类
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct of_device_id btn_match_table[] = {
|
||||||
|
{.compatible = "mykey",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device_id btn_device_ids[] = {
|
||||||
|
{.name = "btn",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver btn_driver=
|
||||||
|
{
|
||||||
|
.probe = btn_probe,
|
||||||
|
.remove = btn_remove,
|
||||||
|
.driver={
|
||||||
|
.name = "btn",
|
||||||
|
.of_match_table = btn_match_table,
|
||||||
|
},
|
||||||
|
.id_table = btn_device_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module_platform_driver(btn_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||||
|
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||||
|
MODULE_VERSION("0.1"); //版本
|
||||||
|
MODULE_DESCRIPTION("btn_driver"); //简单的描述
|
||||||
11
code/Driver/keypad/Makefile
Normal file
11
code/Driver/keypad/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||||
|
rm -rf modules.order *.ko
|
||||||
|
|
||||||
|
obj-m +=mykeypad.o
|
||||||
|
|
||||||
163
code/Driver/keypad/mykeypad.c
Normal file
163
code/Driver/keypad/mykeypad.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的设备函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/platform_device.h> //包含platform函数
|
||||||
|
#include <linux/of.h> //包含设备树相关函数
|
||||||
|
#include <linux/irq.h> //含有IRQ_HANDLED和IRQ_TYPE_EDGE_RISING
|
||||||
|
#include <linux/interrupt.h> //含有request_irq、free_irq函数
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
|
||||||
|
struct input_dev *mykeypad_dev; //定义一个input_dev结构体
|
||||||
|
|
||||||
|
ssize_t volatile *keyadc_ctrl;
|
||||||
|
ssize_t volatile *keyadc_intc;
|
||||||
|
ssize_t volatile *keyadc_ints;
|
||||||
|
ssize_t volatile *keyadc_data;
|
||||||
|
|
||||||
|
static unsigned int key_value = 0; //定义一个变量保存按键值
|
||||||
|
|
||||||
|
static irqreturn_t mykeypad_irq (int irq, void *dev_id) //中断服务函数
|
||||||
|
{
|
||||||
|
ssize_t key_value;
|
||||||
|
/*上报事件*/
|
||||||
|
key_value = ((*keyadc_data)&(0x3f));
|
||||||
|
if(((*keyadc_ints)&(1<<1)) != 0)
|
||||||
|
{
|
||||||
|
if(key_value == 24)
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_A , 1); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
else if(key_value == 17)
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_B, 1); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
else if(key_value == 11)
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_C, 1); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_D, 1); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(((*keyadc_ints)&(1<<4)) != 0)
|
||||||
|
{
|
||||||
|
if(key_value == 24)
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_A , 0); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
else if(key_value == 17)
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_B, 0); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
else if(key_value == 11)
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_C, 0); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input_event(mykeypad_dev, EV_KEY, KEY_D, 0); //上报EV_KEY类型,button按键,1(按下)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input_sync(mykeypad_dev); // 上传同步事件,告诉系统有事件出现
|
||||||
|
*keyadc_ints |= ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4));
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mykeypad_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct resource *res;
|
||||||
|
mykeypad_dev=input_allocate_device(); //向内核申请input_dev结构体
|
||||||
|
set_bit(EV_KEY,mykeypad_dev->evbit); //支持键盘事件
|
||||||
|
set_bit(EV_REP,mykeypad_dev->evbit); //支持键盘重复按事件
|
||||||
|
set_bit(KEY_A,mykeypad_dev->keybit); //支持按键 A
|
||||||
|
set_bit(KEY_B,mykeypad_dev->keybit); //支持按键 B
|
||||||
|
set_bit(KEY_C,mykeypad_dev->keybit); //支持按键 C
|
||||||
|
set_bit(KEY_D,mykeypad_dev->keybit); //支持按键 D
|
||||||
|
|
||||||
|
mykeypad_dev->name = pdev->name; //设备名称
|
||||||
|
mykeypad_dev->phys = "mykeypad/input0"; //设备文件路径
|
||||||
|
mykeypad_dev->open = NULL; //设备打开操作函数
|
||||||
|
mykeypad_dev->close = NULL; //设备关闭操作函数
|
||||||
|
mykeypad_dev->id.bustype = BUS_HOST; //设备总线类型
|
||||||
|
mykeypad_dev->id.vendor = 0x0001; //设备厂家编号
|
||||||
|
mykeypad_dev->id.product = 0x0001; //设备产品编号
|
||||||
|
mykeypad_dev->id.version = 0x0100; //设备版本
|
||||||
|
|
||||||
|
ret = input_register_device(mykeypad_dev); //注册input_dev
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
input_free_device(mykeypad_dev);
|
||||||
|
printk(KERN_ERR "regoster input device failed!\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
mykeypad_dev->name="mykeypad";
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的LRADC_CTRL
|
||||||
|
keyadc_ctrl = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的LRADC_INTC
|
||||||
|
keyadc_intc = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的LRADC_INTS
|
||||||
|
keyadc_ints = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的LRADC_DATA
|
||||||
|
keyadc_data = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
|
||||||
|
ret = devm_request_irq(&pdev->dev, platform_get_irq(pdev, 0), mykeypad_irq, 0, "mykey", (void*)&key_value);
|
||||||
|
*keyadc_ctrl&=0;
|
||||||
|
*keyadc_ctrl |= (2<<24) | (1<<8) | (1<<6);
|
||||||
|
*keyadc_intc |= (1<<4) | (1<<1);
|
||||||
|
*keyadc_ctrl |= (1<<0);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int mykeypad_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
iounmap(keyadc_ctrl); //取消LRADC_CTRL映射
|
||||||
|
iounmap(keyadc_intc); //取消LRADC_INTC映射
|
||||||
|
iounmap(keyadc_ints); //取消LRADC_INTS映射
|
||||||
|
iounmap(keyadc_data); //取消LRADC_DATA映射
|
||||||
|
|
||||||
|
input_unregister_device(mykeypad_dev); //卸载类下的驱动设备
|
||||||
|
input_free_device(mykeypad_dev); //释放驱动结构体
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct of_device_id mykeypad_match_table[] = {
|
||||||
|
{.compatible = "mykeypad",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device_id mykeypad_device_ids[] = {
|
||||||
|
{.name = "mykeypad",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver mykeypad_driver=
|
||||||
|
{
|
||||||
|
.probe = mykeypad_probe,
|
||||||
|
.remove = mykeypad_remove,
|
||||||
|
.driver={
|
||||||
|
.name = "mykeypad",
|
||||||
|
.of_match_table = mykeypad_match_table,
|
||||||
|
},
|
||||||
|
.id_table = mykeypad_device_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module_platform_driver(mykeypad_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||||
|
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||||
|
MODULE_VERSION("0.1"); //版本
|
||||||
|
MODULE_DESCRIPTION("mykeypad_driver"); //简单的描述
|
||||||
11
code/Driver/led_dev/Makefile
Normal file
11
code/Driver/led_dev/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||||
|
rm -rf modules.order *.ko
|
||||||
|
|
||||||
|
obj-m +=sysfs_led_dev.o
|
||||||
|
|
||||||
141
code/Driver/led_dev/led_dev_old.c
Normal file
141
code/Driver/led_dev/led_dev_old.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的设备函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/platform_device.h> //包含platform函数
|
||||||
|
#include <linux/of.h> //包含设备树相关函数
|
||||||
|
#include <linux/miscdevice.h> //包含misc相关函数
|
||||||
|
|
||||||
|
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||||
|
|
||||||
|
static int misc_led_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
/* GPIOE配置 */
|
||||||
|
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||||
|
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||||
|
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||||
|
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||||
|
printk(KERN_DEBUG"open led!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_close(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
/* GPIOE配置 */
|
||||||
|
printk(KERN_DEBUG"close led!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t status = *((volatile size_t*)gpioe_data);//获取GPIOE12状态
|
||||||
|
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间buff
|
||||||
|
if(ret < 0)
|
||||||
|
printk(KERN_DEBUG"read error!!!\n"); //输出信息
|
||||||
|
else
|
||||||
|
printk(KERN_DEBUG"read led ok!!!\n"); //输出信息
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t status;
|
||||||
|
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的status
|
||||||
|
if(ret < 0)
|
||||||
|
printk(KERN_DEBUG"write error!!!\n"); //输出信息
|
||||||
|
else
|
||||||
|
printk(KERN_DEBUG"write led ok!!!\n"); //输出信息
|
||||||
|
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||||
|
if(status)
|
||||||
|
*((volatile size_t*)gpioe_data) |= (1<<12);//设置GPIOE12状态1
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_operations misc_led_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = misc_led_open,
|
||||||
|
.read = misc_led_read,
|
||||||
|
.write = misc_led_write,
|
||||||
|
.release = misc_led_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct miscdevice misc_led_dev = {
|
||||||
|
.minor = MISC_DYNAMIC_MINOR, //动态分配次设备号
|
||||||
|
.name = "miscled",
|
||||||
|
.fops = &misc_led_ops, //文件操作集
|
||||||
|
};
|
||||||
|
|
||||||
|
static int misc_led_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
misc_register(&misc_led_dev); //注册misc设备
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的GPIOE_CFG0
|
||||||
|
gpioe_cfg0 = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的GPIOE_CFG1
|
||||||
|
gpioe_cfg1 = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的GPIOE_DATA
|
||||||
|
gpioe_data = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的GPIOE_PUL0
|
||||||
|
gpioe_pul0 = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
iounmap(gpioe_cfg0); //取消GPIOE_CFG0映射
|
||||||
|
iounmap(gpioe_cfg1); //取消GPIOE_CFG1映射
|
||||||
|
iounmap(gpioe_data); //取消GPIOE_DATA映射
|
||||||
|
iounmap(gpioe_pul0); //取消GPIOE_PUL0映射
|
||||||
|
misc_deregister(&misc_led_dev); //注销misc设备
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct of_device_id misc_led_match_table[] = {
|
||||||
|
{.compatible = "lite200,misc_led",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device_id misc_led_device_ids[] = {
|
||||||
|
{.name = "misc_led",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver misc_led_driver=
|
||||||
|
{
|
||||||
|
.probe = misc_led_probe,
|
||||||
|
.remove = misc_led_remove,
|
||||||
|
.driver={
|
||||||
|
.name = "misc_led",
|
||||||
|
.of_match_table = misc_led_match_table,
|
||||||
|
},
|
||||||
|
.id_table = misc_led_device_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int misc_led_driver_init(void)
|
||||||
|
{
|
||||||
|
platform_driver_register(&misc_led_driver);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void misc_led_driver_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&misc_led_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(misc_led_driver_init);
|
||||||
|
module_exit(misc_led_driver_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||||
|
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||||
|
MODULE_VERSION("0.1"); //版本
|
||||||
|
MODULE_DESCRIPTION("misc_led_driver"); //简单的描述
|
||||||
141
code/Driver/led_dev/misc_led_dev.c
Normal file
141
code/Driver/led_dev/misc_led_dev.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的设备函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/platform_device.h> //包含platform函数
|
||||||
|
#include <linux/of.h> //包含设备树相关函数
|
||||||
|
#include <linux/miscdevice.h> //包含misc相关函数
|
||||||
|
|
||||||
|
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||||
|
|
||||||
|
static int misc_led_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
/* GPIOE配置 */
|
||||||
|
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||||
|
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||||
|
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||||
|
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||||
|
printk(KERN_DEBUG"open led!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_close(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
/* GPIOE配置 */
|
||||||
|
printk(KERN_DEBUG"close led!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t status = *((volatile size_t*)gpioe_data);//获取GPIOE12状态
|
||||||
|
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间buff
|
||||||
|
if(ret < 0)
|
||||||
|
printk(KERN_DEBUG"read error!!!\n"); //输出信息
|
||||||
|
else
|
||||||
|
printk(KERN_DEBUG"read led ok!!!\n"); //输出信息
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t status;
|
||||||
|
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的status
|
||||||
|
if(ret < 0)
|
||||||
|
printk(KERN_DEBUG"write error!!!\n"); //输出信息
|
||||||
|
else
|
||||||
|
printk(KERN_DEBUG"write led ok!!!\n"); //输出信息
|
||||||
|
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||||
|
if(status)
|
||||||
|
*((volatile size_t*)gpioe_data) |= (1<<12);//设置GPIOE12状态1
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_operations misc_led_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = misc_led_open,
|
||||||
|
.read = misc_led_read,
|
||||||
|
.write = misc_led_write,
|
||||||
|
.release = misc_led_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct miscdevice misc_led_dev = {
|
||||||
|
.minor = MISC_DYNAMIC_MINOR, //动态分配次设备号
|
||||||
|
.name = "miscled",
|
||||||
|
.fops = &misc_led_ops, //文件操作集
|
||||||
|
};
|
||||||
|
|
||||||
|
static int misc_led_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
misc_register(&misc_led_dev); //注册misc设备
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的GPIOE_CFG0
|
||||||
|
gpioe_cfg0 = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的GPIOE_CFG1
|
||||||
|
gpioe_cfg1 = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的GPIOE_DATA
|
||||||
|
gpioe_data = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的GPIOE_PUL0
|
||||||
|
gpioe_pul0 = ioremap(res->start,(res->end - res->start)+1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int misc_led_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
iounmap(gpioe_cfg0); //取消GPIOE_CFG0映射
|
||||||
|
iounmap(gpioe_cfg1); //取消GPIOE_CFG1映射
|
||||||
|
iounmap(gpioe_data); //取消GPIOE_DATA映射
|
||||||
|
iounmap(gpioe_pul0); //取消GPIOE_PUL0映射
|
||||||
|
misc_deregister(&misc_led_dev); //注销misc设备
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct of_device_id misc_led_match_table[] = {
|
||||||
|
{.compatible = "lite200,misc_led",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device_id misc_led_device_ids[] = {
|
||||||
|
{.name = "misc_led",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver misc_led_driver=
|
||||||
|
{
|
||||||
|
.probe = misc_led_probe,
|
||||||
|
.remove = misc_led_remove,
|
||||||
|
.driver={
|
||||||
|
.name = "misc_led",
|
||||||
|
.of_match_table = misc_led_match_table,
|
||||||
|
},
|
||||||
|
.id_table = misc_led_device_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int misc_led_driver_init(void)
|
||||||
|
{
|
||||||
|
platform_driver_register(&misc_led_driver);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void misc_led_driver_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&misc_led_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(misc_led_driver_init);
|
||||||
|
module_exit(misc_led_driver_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||||
|
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||||
|
MODULE_VERSION("0.1"); //版本
|
||||||
|
MODULE_DESCRIPTION("misc_led_driver"); //简单的描述
|
||||||
100
code/Driver/led_dev/sysfs_led_dev.c
Normal file
100
code/Driver/led_dev/sysfs_led_dev.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的设备函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/kobject.h> //包含sysfs文件系统对象类
|
||||||
|
#include <linux/sysfs.h> //包含sysfs操作文件函数
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
|
||||||
|
#define GPIOE_CFG0 (0x01C20890)
|
||||||
|
#define GPIOE_CFG1 (0x01C20894)
|
||||||
|
#define GPIOE_DATA (0x01C208A0)
|
||||||
|
#define GPIOE_PUL0 (0x01C208AC)
|
||||||
|
|
||||||
|
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||||
|
|
||||||
|
static int led_status = 0; //定义一个led状态变量
|
||||||
|
|
||||||
|
static struct kobject *led_kobj; //定义一个led_kobj
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t led_show(struct kobject* kobjs,struct kobj_attribute *attr,char *buf)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO "Read led\n");
|
||||||
|
return sprintf(buf,"The led_status status is = %d\n",led_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t led_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO "led status store\n");
|
||||||
|
if(0 == memcmp(buf,"on",2))
|
||||||
|
{
|
||||||
|
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||||
|
led_status = 1;
|
||||||
|
}
|
||||||
|
else if(0 == memcmp(buf,"off",3))
|
||||||
|
{
|
||||||
|
*((volatile size_t*)gpioe_data) |= (1<<12);//设置GPIOE12状态1
|
||||||
|
led_status = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printk(KERN_INFO "Not support cmd\n");
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//定义一个led_attr对象属性
|
||||||
|
static struct kobj_attribute led_attr = __ATTR(led_status,0660,led_show,led_store);
|
||||||
|
|
||||||
|
static int __init sysfs_led_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
led_kobj = kobject_create_and_add("sys_led",NULL);
|
||||||
|
if(led_kobj == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO"create led_kobj failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = sysfs_create_file(led_kobj, &led_attr.attr);
|
||||||
|
if(ret != 0)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO"create sysfa file failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gpioe_cfg0 = ioremap(GPIOE_CFG0,4); //将GPIOE_CFG0物理地址映射为虚拟地址
|
||||||
|
gpioe_cfg1 = ioremap(GPIOE_CFG1,4); //将GPIOE_CFG1物理地址映射为虚拟地址
|
||||||
|
gpioe_data = ioremap(GPIOE_DATA,4); //将GPIOE_DATA物理地址映射为虚拟地址
|
||||||
|
gpioe_pul0 = ioremap(GPIOE_PUL0,4); //将GPIOE_PUL0物理地址映射为虚拟地址
|
||||||
|
|
||||||
|
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||||
|
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||||
|
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||||
|
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||||
|
|
||||||
|
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit sysfs_led_exit(void)
|
||||||
|
{
|
||||||
|
sysfs_remove_file(led_kobj,&led_attr.attr); //删除属性
|
||||||
|
kobject_put(led_kobj); //删除对象
|
||||||
|
printk(KERN_INFO "Goodbye!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(sysfs_led_init);
|
||||||
|
module_exit(sysfs_led_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("1477153217@qq.com");
|
||||||
|
MODULE_DESCRIPTION("sysfs led");
|
||||||
|
MODULE_VERSION("0.1");
|
||||||
11
code/Driver/w25q128/Makefile
Normal file
11
code/Driver/w25q128/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||||
|
rm -rf modules.order *.ko
|
||||||
|
|
||||||
|
obj-m +=w25q128.o
|
||||||
|
|
||||||
115
code/Driver/w25q128/w25q128.c
Normal file
115
code/Driver/w25q128/w25q128.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的设备函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include <linux/platform_device.h> //包含platform函数
|
||||||
|
#include <linux/of.h> //包含设备树相关函数
|
||||||
|
#include <linux/spi/spi.h>
|
||||||
|
#include <linux/kobject.h> //包含sysfs文件系统对象类
|
||||||
|
#include <linux/sysfs.h> //包含sysfs操作文件函数
|
||||||
|
|
||||||
|
#define ERASE_OPCODE 0x20 //擦除操作码
|
||||||
|
#define R_STS_OPCODE 0x35 //读状态操作码
|
||||||
|
|
||||||
|
static char tx_data[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
|
||||||
|
static char rx_data[16] = {0};
|
||||||
|
|
||||||
|
static struct kobject *w25qxx_kobj; //定义一个led_kobj
|
||||||
|
struct spi_transfer xfer;
|
||||||
|
struct spi_device *w25qxx_spi; //保存spi设备结构体
|
||||||
|
static ssize_t w25qxx_show(struct kobject* kobjs,struct kobj_attribute *attr,char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf,"read status register=%d\n",rx_data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t w25qxx_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int erase_addr=0x123456;
|
||||||
|
tx_data[0]=ERASE_OPCODE;
|
||||||
|
tx_data[1]=(erase_addr>>16)&0xff;
|
||||||
|
tx_data[2]=(erase_addr>>8)&0xff;
|
||||||
|
tx_data[3]=(erase_addr)&0xff;
|
||||||
|
xfer.len = 4;
|
||||||
|
ret = spi_sync_transfer(w25qxx_spi,&xfer,1); //擦除操作
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO"erase w25q128 failed!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_data[0]=R_STS_OPCODE;
|
||||||
|
ret = spi_write_then_read(w25qxx_spi,tx_data,1,rx_data,1);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kobj_attribute w25qxx_attr = __ATTR(w25q128_dev,0660,w25qxx_show,w25qxx_store);
|
||||||
|
|
||||||
|
static void w25qxx_init(void)
|
||||||
|
{
|
||||||
|
xfer.tx_buf = tx_data;
|
||||||
|
xfer.rx_buf = rx_data;
|
||||||
|
xfer.len = sizeof(tx_data);
|
||||||
|
xfer.bits_per_word = 8;
|
||||||
|
memset(rx_data,0,16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int w25qxx_probe(struct spi_device *spi)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
w25qxx_kobj = kobject_create_and_add("sys_w25qxx",NULL);
|
||||||
|
if(w25qxx_kobj == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO"create w25qxx_kobj failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = sysfs_create_file(w25qxx_kobj, &w25qxx_attr.attr);
|
||||||
|
if(ret != 0)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO"create w25q128_dev file failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
w25qxx_spi = spi_dev_get(spi);
|
||||||
|
w25qxx_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int w25qxx_remove(struct spi_device *spi)
|
||||||
|
{
|
||||||
|
sysfs_remove_file(w25qxx_kobj, &w25qxx_attr.attr); //删除属性
|
||||||
|
kobject_put(w25qxx_kobj); //删除对象
|
||||||
|
printk(KERN_INFO "exit sysfs w25qxx!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct of_device_id w25qxx_match_table[] = {
|
||||||
|
{.compatible = "test,w25qxx",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct spi_device_id w25qxx_ids[] = {
|
||||||
|
{.name = "w25q128",},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct spi_driver w25qxx_cdev = {
|
||||||
|
.driver = {
|
||||||
|
.name = "w25qxx",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = w25qxx_match_table,
|
||||||
|
},
|
||||||
|
.probe = w25qxx_probe,
|
||||||
|
.remove = w25qxx_remove,
|
||||||
|
.id_table = w25qxx_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module_spi_driver(w25qxx_cdev);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||||
|
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||||
|
MODULE_VERSION("0.1"); //版本
|
||||||
|
MODULE_DESCRIPTION("w25qxx_driver"); //简单的描述
|
||||||
11
code/led_dev/Makefile
Normal file
11
code/led_dev/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||||
|
rm -rf modules.order *.ko
|
||||||
|
|
||||||
|
obj-m +=led_dev.o
|
||||||
|
|
||||||
140
code/led_dev/led_dev.c
Normal file
140
code/led_dev/led_dev.c
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||||
|
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||||
|
#include <linux/device.h> //含有类相关的设备函数
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
|
||||||
|
#define GPIOE_CFG0 (0x01C20890)
|
||||||
|
#define GPIOE_CFG1 (0x01C20894)
|
||||||
|
#define GPIOE_DATA (0x01C208A0)
|
||||||
|
#define GPIOE_PUL0 (0x01C208AC)
|
||||||
|
|
||||||
|
static dev_t led_dev_num; //定义一个设备号
|
||||||
|
static struct cdev *led_dev; //定义一个设备管理结构体指针
|
||||||
|
static struct class *led_class; //定义一个设备类
|
||||||
|
static struct device *led0; //定义一个设备
|
||||||
|
|
||||||
|
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||||
|
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||||
|
|
||||||
|
|
||||||
|
static int led_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
/* GPIOE配置 */
|
||||||
|
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||||
|
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||||
|
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||||
|
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||||
|
*((volatile size_t*)gpioe_data) &= ~(1<<16); //清除数据寄存器
|
||||||
|
printk(KERN_DEBUG"open led!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int led_close(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
/* GPIOE配置 */
|
||||||
|
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||||
|
*((volatile size_t*)gpioe_cfg1) |= (7<<16); //配置GPIOE12为输出模式
|
||||||
|
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||||
|
*((volatile size_t*)gpioe_data) &= ~(1<<16); //清除数据寄存器
|
||||||
|
printk(KERN_DEBUG"close led!!!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t status = *((volatile size_t*)gpioe_data);//获取GPIOE12状态
|
||||||
|
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间buff
|
||||||
|
if(ret < 0)
|
||||||
|
printk(KERN_DEBUG"read error!!!\n"); //输出信息
|
||||||
|
else
|
||||||
|
printk(KERN_DEBUG"read led ok!!!\n"); //输出信息
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t status;
|
||||||
|
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的status
|
||||||
|
if(ret < 0)
|
||||||
|
printk(KERN_DEBUG"write error!!!\n"); //输出信息
|
||||||
|
else
|
||||||
|
printk(KERN_DEBUG"write led ok!!!\n"); //输出信息
|
||||||
|
*((volatile size_t*)gpioe_data) = status;//设置GPIOE12状态
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static struct file_operations led_ops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = led_open,
|
||||||
|
.read = led_read,
|
||||||
|
.write = led_write,
|
||||||
|
.release = led_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init led_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
led_dev = cdev_alloc(); //动态申请一个设备结构体
|
||||||
|
if(led_dev == NULL)
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ret = alloc_chrdev_region(&led_dev_num,0,1,"led"); //动态申请一个设备号
|
||||||
|
if(ret == 0)
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
led_dev->owner = THIS_MODULE; //初始化设备管理结构体的owner为THIS_MODULE
|
||||||
|
led_dev->ops = &led_ops; //初始化设备操作函数指针为led_ops函数
|
||||||
|
cdev_add(led_dev,led_dev_num,1); //将设备添加到内核中
|
||||||
|
led_class = class_create(THIS_MODULE, "led_class"); //创建一个类
|
||||||
|
if(led_class == NULL)
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
led0 = device_create(led_class,NULL,led_dev_num,NULL,"led0"); //创建一个设备
|
||||||
|
if(IS_ERR(led0))
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
gpioe_cfg0 = ioremap(GPIOE_CFG0,4); //将GPIOE_CFG0物理地址映射为虚拟地址
|
||||||
|
gpioe_cfg1 = ioremap(GPIOE_CFG1,4); //将GPIOE_CFG1物理地址映射为虚拟地址
|
||||||
|
gpioe_data = ioremap(GPIOE_DATA,4); //将GPIOE_DATA物理地址映射为虚拟地址
|
||||||
|
gpioe_pul0 = ioremap(GPIOE_PUL0,4); //将GPIOE_PUL0物理地址映射为虚拟地址
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
printk(KERN_WARNING"led_init failed!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit led_exit(void)
|
||||||
|
{
|
||||||
|
cdev_del(led_dev); //从内核中删除设备管理结构体
|
||||||
|
unregister_chrdev_region(led_dev_num,1); //注销设备号
|
||||||
|
device_destroy(led_class,led_dev_num); //删除设备节点
|
||||||
|
class_destroy(led_class); //删除设备类
|
||||||
|
iounmap(gpioe_cfg0); //取消GPIOE_CFG0映射
|
||||||
|
iounmap(gpioe_cfg1); //取消GPIOE_CFG1映射
|
||||||
|
iounmap(gpioe_data); //取消GPIOE_DATA映射
|
||||||
|
iounmap(gpioe_pul0); //取消GPIOE_PUL0映射
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(led_init);
|
||||||
|
module_exit(led_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||||
|
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||||
|
MODULE_VERSION("0.1"); //版本
|
||||||
|
MODULE_DESCRIPTION("led_dev"); //简单的描述
|
||||||
|
|
||||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user