MTK开发之—为上层提供简易操作文件

背景

在实际开发中,底层驱动往往要暴露一些接口供上层应用,比如需要上层对一个gpio进行操作,应用层没办法直接去控制gpio,只能通过驱动层来间接调用,方式有很多,可以将gpio封装到一个字符设备中,或者直接用misc类注册等等,因linux下一切皆文件,我们也可以在驱动层将gpio封装成文件,让应用层操作文件方式来操作gpio;

想必做过mcu开发的朋友对AT指令不陌生,AT指令后面加 ‘?’ 号表示查询,加 ‘=’ 表示设置,同样的,在应用层或者adb下,我们可以通过cat与echo对一个文件进行读写,非常方便上层应用进行操作,所以本篇是为上层提供这样一个可以这样方便操作文件的方法,并且驱动代码尽量精简,方便模板化使用!

添加设备节点

驱动中设备树是常用的,要使用一个gpio,首先要在设备树中添加相应节点,如下所示:

可以将该内容放到根节点下,就描述了下属性为"misc,ctrl",和一个gpio的引脚信息

&misc {
	compatible = "misc,ctrl";
	boot-gpio = <&pio 28 0>;
};

驱动代码

#include <linux/gpio.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/syscalls.h>
#include <linux/types.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
//gpio设备结构体
struct gpio_dev{
	int major;				//设备号
	struct class *cls;		//类
	struct device_node *nd;	//设备节点
	int boot_gpio;			//gpio
};
struct gpio_dev gpio_msg;
//
//写函数,echo操作时调用的是该函数
static ssize_t boot_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	int val = 0, rc = 0;
	rc = kstrtouint(buf, 0, &val);
	if (rc < 0)	return rc;
	
	if (val == 1) {
		if (gpio_is_valid(gpio_msg.boot_gpio))
			gpio_set_value_cansleep(gpio_msg.boot_gpio, 1);
	}
	else {
		if (gpio_is_valid(gpio_msg.boot_gpio))
			gpio_set_value_cansleep(gpio_msg.boot_gpio, 0);
	}
	return count;
}
//读函数,cat操作时调用的是该函数
static ssize_t boot_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	ssize_t len = 0;
	len += snprintf(buf + len, PAGE_SIZE - len, "boot-pin=%d\n",
			gpio_get_value(gpio_msg.boot_gpio));
	return len;
}
//DEVICE_ATTR是个宏,展开就是定义了一个dev_attr_boot的结构体
//第二个参数是文件所有者/用户组/其它的权限设置,第三个和第四个参数是读写回调函数
static DEVICE_ATTR(boot, S_IRWXU | S_IRWXUGO, boot_show, boot_store);
//
struct file_operations my_test_ops = {
    .owner  = THIS_MODULE,
};

static int gpio_msg_probe(struct platform_device *dev)
{
	int ret = 0;
	struct device *mydev;
	pr_info("%s: enter\n", __func__);
	//从设备树跟节点根据"misc,ctrl"属性查找节点
	gpio_msg.nd = of_find_compatible_node(NULL, NULL, "misc,ctrl");
	if(gpio_msg.nd == NULL) {
		printk("beep node not find!\r\n");
		return -EINVAL;
	} 
	//在节点下查找"boot-gpio"名字的gpio号
	gpio_msg.boot_gpio = of_get_named_gpio(gpio_msg.nd, "boot-gpio", 0);
	if((gpio_msg.boot_gpio < 0)) {
		printk("can't get gpio_msg-gpio");
		return -EINVAL;
	}
	//请求使用gpio,也是为了告诉别人改gpio被我承包了,然后设置gpio输出0
	ret |= gpio_request(gpio_msg.boot_gpio, "boot_gpio28");
	ret |= gpio_direction_output(gpio_msg.boot_gpio, 0);
	if(ret < 0) {
		printk("can't set gpio!\r\n");
	}
	//下面就是字符设备申请设备号、创建类、创建设备的那一套
	gpio_msg.major = register_chrdev(0, "my_test", &my_test_ops);
	gpio_msg.cls = class_create(THIS_MODULE, "gpio_class");
	mydev = device_create(gpio_msg.cls, 0, MKDEV(gpio_msg.major,0), NULL, "gpio-ctrl");
	//在mydev创建的gpio-ctrl目录下创建文件
    if(sysfs_create_file(&(mydev->kobj), &dev_attr_boot.attr)){    
		printk("%s: sysfs_create_file fail\n", __func__);
        return -1;
	}
	pr_info("%s: success\n", __func__);
	return 0;
}

static int gpio_msg_remove(struct platform_device *dev)
{
	gpio_set_value(gpio_msg.boot_gpio, 0);
	gpio_set_value(gpio_msg.reset_gpio, 0);
	return 0;
}

 static const struct of_device_id gpio_of_match[] = {
     { .compatible = "misc,ctrl"},
     { /* Sentinel */ }
 };

static struct platform_driver gpio_driver = {
     .driver     = {
         .name   = "mt8163-gpio",         /* 驱动名字,用于和设备匹配 */
         .of_match_table = gpio_of_match, /* 设备树匹配表          */
     },
     .probe      = gpio_msg_probe,
     .remove     = gpio_msg_remove,
};
module_platform_driver(gpio_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("mstar");

编译验证

source build/envsetup.sh
lunch 项目选项
make bootimage -j8

在这里插入图片描述
烧录之后重新上电,进入adb:

adb shell
因为我们创建了class,所以如果正常的话在/sys/class下会有我们所创建的文件
cd /sys/class

gpio_class就是我们通过class_create创建的类,gpio-ctrl是我们通过device_create创建的设备,而其下的其它文件则是sysfs_create_file函数创建的,而我们提供给应用层的boot文件也在其中,如下:

ls -l  
//驱动中如下这条语句就设置了权限,可读可写可执行
static DEVICE_ATTR(boot, S_IRWXU | S_IRWXUGO, boot_show, boot_store);

可以看到各文件的详细信息,包括所有者权限,注意到了没有
cat boot时会调用boot_show函数
echo x > boot时会调用boot_store
如下所示,读写都正常.
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东皇※太一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值