跟着韦老师学的,不过使用的是orangepi
写的比较简单,请配合韦老师的视频食用
button_drv.h
//button_drv.h
#ifndef _BUTTON__DRV_H
#define _BUTTON__DRV_H
struct button_operations
{
int count;
void (*init) (int which);
int (*read) (int which);
};
void register_button_operation(struct button_operations *opr);
void unregister_button_operation(void);
#endif
button_drv.c
//button_drv.c
#include <linux/fs.h> //file_operations声明
#include <linux/module.h> //module_init module_exit声明
#include <linux/init.h> //__init __exit 宏定义声明
#include <linux/device.h> //class devise声明
#include <linux/uaccess.h> //copy_from_user 的头文件
#include <linux/types.h> //设备号 dev_t 类型声明
#include <asm/io.h> //ioremap iounmap的头文件
#include "button_drv.h"
static int major = 0; // find dirver funtion
// static int minor =0; //次设备号 what ever
static struct class *button_class;
static struct button_operations *p_button_opr;
int button_open(struct inode *node, struct file *file)
{
int minor = iminor(node); // give minor from node
p_button_opr->init(minor);
return 0;
}
ssize_t button_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{
int minor = iminor(file_inode(file)); // give minor from file
char level;
level = p_button_opr->read(minor);
copy_to_user(buf, &level, sizeof(level));
return 0;
}
void register_button_operation(struct button_operations *opr)
{
int i;
p_button_opr = opr;
for (i = 0; i < opr->count; i++)
{
device_create(button_class, NULL, MKDEV(major, i), NULL, "clx_button%d", i);
}
}
void unregister_button_operation(void)
{
int i;
for (i = 0; i < p_button_opr->count; i++)
{
device_destroy(button_class, MKDEV(major, i));
}
}
EXPORT_SYMBOL(register_button_operation);
EXPORT_SYMBOL(unregister_button_operation);
static struct file_operations button_fops = {
.open = button_open,
.read = button_read,
};
int clx_button_init(void)
{
major = register_chrdev(0, "clx_button", &button_fops);
button_class = class_create(THIS_MODULE, "clx_button");
if (IS_ERR(button_class))
return -1;
return 0;
}
void clx_button_exit(void)
{
class_unregister(button_class);
unregister_chrdev(major, "clx_button");
}
// 注册模块加载函数
module_init(clx_button_init);
// 卸载模块加载函数
module_exit(clx_button_exit);
// 开源信息
MODULE_LICENSE("GPL");
button_dev.c
//button_dev.c
#include <linux/fs.h> //file_operations声明
#include <linux/module.h> //module_init module_exit声明
#include <linux/init.h> //__init __exit 宏定义声明
#include <linux/device.h> //class devise声明
#include <linux/uaccess.h> //copy_from_user 的头文件
#include <linux/types.h> //设备号 dev_t 类型声明
#include <asm/io.h>
#include "button_drv.h"
#define GPIO_BASE 0x0300B000
#define GPIOC_BASE GPIO_BASE + 2 * 0x24
#define GPIOF_BASE GPIO_BASE + 5 * 0x24
#define GPIOG_BASE GPIO_BASE + 6 * 0x24
#define GPIOH_BASE GPIO_BASE + 7 * 0x24
#define PIO_POW_MOD_SEL 0x0300B340
#define PIO_POW_MS_CTL 0x0300B344
#define PIO_POW_VAL 0x0300B348
static struct Pn_CFG {
unsigned int Pn_CFG0;
unsigned int Pn_CFG1;
unsigned int Pn_CFG2;
unsigned int Pn_CFG3;
unsigned int Pn_DAT;
unsigned int Pn_DRV0;
unsigned int Pn_DRV1;
unsigned int Pn_PUL0;
unsigned int Pn_PUL1;
};
static struct Pn_INT_CFG {
unsigned int Pn_INT_CFG0;
unsigned int Pn_INT_CFG1;
unsigned int Pn_INT_CFG2;
unsigned int Pn_INT_CFG3;
unsigned int Pn_INT_STL;
unsigned int Pn_INT_STA;
unsigned int Pn_INT_DEB;
};
struct Pn_CFG* PC_CFG;
static void clx_button_init(int which)
{
printk("start init\n");
PC_CFG = ioremap(GPIOC_BASE,sizeof(struct Pn_CFG));
//in mode
PC_CFG->Pn_CFG1 &= ~((unsigned int)7 << (12%8)*4);//使用GPIOC_12引脚
//pull up
PC_CFG->Pn_PUL0 |= ((unsigned int)1 << 12);
printk("Pn_CFG1 = %#x p = %p , Pn_PUL0 = %#x p = %p ",PC_CFG->Pn_CFG1,PC_CFG->Pn_CFG1,(PC_CFG->Pn_PUL0),PC_CFG->Pn_PUL0);//output 0x
}
static int clx_button_read(int which)
{
printk("start read\n");
if(~(PC_CFG->Pn_CFG1 >> (12%8)*4) & 7 == 7)//判断引脚是否为输入模式
{
if((PC_CFG->Pn_DAT >> 12)&0x01 == 1)//判断读取引脚的值是否为1
printk("read data is high\n");
else printk("read data is low\n");
return 0;
}
else
return -1;
}
static struct button_operations clx_button_opr = {
.count = 2,
.init = clx_button_init,
.read = clx_button_read,
};
int __init clx_button_drv_init(void)
{
register_button_operation(&clx_button_opr);
return 0;
}
void __exit clx_button_drv_exit(void)
{
unregister_button_operation();
}
module_init(clx_button_drv_init);
module_exit(clx_button_drv_exit);
// 开源信息
MODULE_LICENSE("GPL");
Makefile
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
KERN_DIR = /home/coolx/orangepi-build/kernel/orange-pi-6.1-sun50iw9
all:
make -C $(KERN_DIR) M=`pwd` modules
#$(CROSS_COMPILE)gcc -o led_dev led_dev.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
#rm -f led_dev
#obj-m += pindriver.o
obj-m += led_dev.o led_tree_drv.o
obj-m += button_drv.o button_dev.o
编译模块后上传到开发板
orangepi@orangepizero2w:~$ sudo insmod button_drv.ko
orangepi@orangepizero2w:~$ sudo insmod button_dev.ko
orangepi@orangepizero2w:~$ sudo chmod 666 /dev/clx_button0
orangepi@orangepizero2w:~$ sudo dmesg -c
//短接PC12和GND(上图圈出)
orangepi@orangepizero2w:~$ cat /dev/clx_button0
orangepi@orangepizero2w:~$ dmesg
[170038.569863] start init
[170038.569920] Pn_CFG1 = 0x17107760 p = 000000006cd91c13 , Pn_PUL0 = 0x5541 p = 000000006633a63a
[170038.570021] start read
[170038.570035] read data is low
//断开PC12和GND(上图圈出)
orangepi@orangepizero2w:~$ cat /dev/clx_button0
orangepi@orangepizero2w:~$ dmesg
[170038.569863] start init
[170038.569920] Pn_CFG1 = 0x17107760 p = 000000006cd91c13 , Pn_PUL0 = 0x5541 p = 000000006633a63a
[170038.570021] start read
[170038.570035] read data is low
[170293.852490] start init
[170293.852546] Pn_CFG1 = 0x17107760 p = 000000006cd91c13 , Pn_PUL0 = 0x5541 p = 000000006633a63a
[170293.852649] start read
[170293.852663] read data is high
参考链接:
https://www.100ask.net/
https://www.bilibili.com/video/BV1w4411B7a4?p=116