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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//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

MTK开发之—为上层提供简易操作文件_第1张图片
烧录之后重新上电,进入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
如下所示,读写都正常.
MTK开发之—为上层提供简易操作文件_第2张图片

你可能感兴趣的:(MTK开发日志,linux,嵌入式)