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