根据项目需求,需要编写文件节点供上层apk操作底层gpio口,其中在proc文件系统下,创建自己的可读写节点,最为简单。
首先添加需要使用到的linux内核头文件:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <linux/backlight.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <video/display_timing.h>
#include <video/mipi_display.h>
#include <video/of_display_timing.h>
#include <video/videomode.h>
添加自定义宏
#define USER_ROOT_DIR "gpio_control_config"
#define USER_ENTRY3 "identity"
#define YLMK_EN_GPIO 169 //gpio5 c1 -->medical boot
#define BLOOD_OXYGEN 68 //gpio2 b4 -->blood oxygen
#define IDENTITY 219 //gpio7 a3 -->identity
定义proc结构体指针
static struct proc_dir_entry *gpio_control_config;
static struct proc_dir_entry *identity;
static char msg[255]; //数据缓冲区
添加节点入口和出口,在系统加载这个字符驱动时,会从module_init()
进入,然后调用其中的回调函数在这儿也就是proc_identity_init
函数。
然后我们在初始化中,通过proc_mkdir创建一个proc文件节点下的文件夹。其中的参数USER_ROOT_DIR :文件夹的名字。
NULL:文件夹所属的父节点。为MULL时则表示就在proc下。
然后proc_create函数则就是创建节点,其中的参数:
USER_ENTRY3:节点名称
0777 :节点拥有的系统权限
gpio_control_config :节点所属的父节点。为NULL时表示就在proc下。
identity_fops :文件节点的操作函数,为struct file_operations *
类型
卸载驱动时则调用module_exit()
,通过remove_proc_entry()
函数来移除节点,注意需要先移除创建的子节点,然后再移除父节点。
static int proc_identity_init(void)
{
//gpio_request(YLMK_EN_GPIO,"medical_boot");
gpio_request(BLOOD_OXYGEN,"blood_oxygen");
gpio_request(IDENTITY,"identity");
//gpio_direction_output(YLMK_EN_GPIO,0);
gpio_direction_output(IDENTITY,0);
gpio_control_config = proc_mkdir(USER_ROOT_DIR,NULL);
identity = proc_create(USER_ENTRY3, 0777, gpio_control_config, &identity_fops);
return 0;
}
static void proc_identity_exit(void)
{
remove_proc_entry(USER_ENTRY1,gpio_control_config);
remove_proc_entry(USER_ROOT_DIR,NULL);
printk(KERN_INFO "All proc entry removed !\n");
}
module_init(proc_identity_init);
module_exit(proc_identity_exit);
MODULE_LICENSE("GPL");
添加file_operations 操作函数(操作函数可根据自己的需要自行编写,我这儿只做了如echo on > /proc/gpio_control_config/identity 则给相应的gpio上电):
ssize_t identity_read(struct file *filp, char __user *buf, size_t len, loff_t *ops)
{
int ret;
char val[20];
sprintf(val, "%s", msg);
ret = simple_read_from_buffer(buf, len, ops, val, strlen(val));
return ret;
}
ssize_t identity_write(struct file *file,const char __user *buffer,size_t count,loff_t *ops)
{
//medical_boot control
if(copy_from_user((void *)msg,(const void __user *)buffer,count))
return -EFAULT;
//identity control
if(strcmp(msg,"on") == 1){
gpio_direction_output(IDENTITY,1);
}
else{
gpio_direction_output(IDENTITY,0);
}
return count;
}
static struct file_operations identity_fops = {
.owner = THIS_MODULE,
.write = identity_write, //echo
.read = identity_read, //cat
};
到这儿一个proc节点就编写完成了,然后需要将该驱动编译到内核中去,在kernel/driver/misc/目录下修改Makefile 和Kconfig文件我的驱动文件名字为ylmk_config.c。
Makefile中添加:
obj-$(CONFIG_YLMK_CONFIG) += ylmk_config.o
Kconfig中添加:
config YLMK_CONFIG
tristate "ylmk config Reader Controller support"
default n
help
say Y here to enable Rockchip Smartcard Reader Controller driver
for Soc such as RK3128,RK322x,RK3288,RK3368,RK3366 and etc.
我们平台需要将新增的驱动文件写入默认配置,在/kernel/arch/arm/configs/下修改rockchip_defconfig文件:
添加
CONFIG_YLMK_CONFIG=y
重新编译并烧录kernel即可。