安卓系统节点创建(个人笔记)

节点的作用

安卓是基于linux的虚拟机。而linux系统一切都是文件,节点类似创建一个文件。通常创建的文件节点一般有以下作用。
1、用于上层读取设备信息。例如屏幕名称,摄像头名称,TP固件版本等信息。
2、用于上层向底层写入信息。例如TP模拟贴脸灭屏功能的开启关闭。

节点创建的方法

节点创建的方法有很多,BSP工程师常见的一般有两种。

方法一(device_create_file)

代码原型如下:

int device_create_file(struct device *dev, struct device_attribute *attr);

参数
	dev:指向设备结构体的指针。
	attr:指向设备属性结构体的指针。

以上参数中dev创建的位置决定了attr节点的位置。
例如创建了一个platform_device的dev,通过这个dev创建的节点,节点路径为:/sys/devices/platform/(dev的名称)/(attr节点的名称)

/* add for miki-tpd*/
示例代码为MTK平台创建TP固件版本号的示例,路径为:/sys/devices/platform/miki-tpd/tp_firmware_version
/*add node tp_version*/
static ssize_t ovt_tcm_tp_version_show(struct device *dev,
		struct device_attribute *attr, char *buf)
	{

	char *ptr = buf;

	printk("ovt_tp_version_show\n");

	ptr += sprintf(ptr," Firmware:%d \n",g_tcm_hcd->packrat_number);

	printk("ovt_tp_version_show:%s\n",ptr);

	return (ptr-buf);
}

static DEVICE_ATTR(tp_firmware_version, 0664, ovt_tcm_tp_version_show, NULL);

static int mikinode_probe(struct platform_device *dev)
{
    int ret = 0;
    printk("%s: enty\n",__func__);
    ret = device_create_file(&(dev->dev),&dev_attr_tp_firmware_version);
    if(ret)
    {
        printk("%s: device_create_file tp_firmware_version failed\n",__func__);
    }
	ret = device_create_file(&(dev->dev),&dev_attr_touch_ic);
    if(ret)
    {
        printk("%s: device_create_file touch_ic failed\n",__func__);
    }
	ret = device_create_file(&(dev->dev),&dev_attr_tp_vendor);
    if(ret)
    {
        printk("%s: device_create_file tp_vendor failed\n",__func__);
    }
    return ret;
}

static struct platform_driver mikinode_driver = {
    .driver = {
        .name = "miki-tpd",
        .owner = THIS_MODULE,
    },
    .probe = mikinode_probe,

};
#ifdef CONFIG_OF
static struct platform_device mikinode_device = {
    .name = "miki-tpd",
    .id = -1,
};
#endif
static int mikinode_init(void)
{
    int err;
    err = platform_device_register(&mikinode_device);
    if(err)
    {
        printk("mikinode_init: failed to register device\n");
        return -ENODEV;
    }
    err = platform_driver_register(&mikinode_driver);
    if(err)
    {
        printk("mikinode_init: failed to register driver\n");
        return -ENODEV;
    }
    return err;
}

static void mikinode_exit(void)
{
	printk("mikinode_exit: remove device\n");
    platform_device_unregister(&mikinode_device);
}

/* add miki-tpd end*/
以上代码为引用代码更改的
引用路径文末提供

以下代码为新建一个虚拟的节点,故节点位置为:/sys/devices/virtual/(class名称)/(device名称)/(节点名称)

//add
static ssize_t cts_tp_version_show(struct device *dev,
	struct device_attribute *attr, char *buf)
	{
    extern struct chipone_ts_data *cts_data;
	char *ptr = buf;
    
	cts_info("cts_tp_version_show");

	ptr += sprintf(ptr,"IC type : icnl9916\n");
	ptr += sprintf(ptr,"Firmware : 0x%x\n",cts_data->cts_dev.fwdata.version);
	cts_info("cts_tp_version_show:%s",ptr);

	return (ptr-buf);
}

static DEVICE_ATTR(tp_version, S_IRUSR, cts_tp_version_show, NULL);


static struct class *touchscreen_class;
static struct device *touchscreen_class_dev;
//end

在调用的代码内添加
//add

    touchscreen_class = class_create(THIS_MODULE, "touchscreen");
    if (IS_ERR(touchscreen_class)) {
		cts_info("create touchscreen class failed");
		return -EPERM;
	}
    	touchscreen_class_dev = device_create(touchscreen_class, NULL,0,NULL, "device");
	if (IS_ERR(touchscreen_class_dev)) {
		cts_info("create touchscreen device failed");
		return -EPERM;
	}

	ret = device_create_file(touchscreen_class_dev, &dev_attr_tp_version);
	if(ret)
	{
		cts_info("create /sys/devices/virtual/touchscreen/device/tp_version failed\n");
	}

//end

方法二(sysfs_create_group)

代码原型如下:

int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);
	参数
		kobj:内核对象的指针。
		grp:属性组的指针,包含一组属性定义。

以上函数中kobj参数决定了节点创建的文件路径,该参数需要使用函数kobject_create_and_add创建一个对象。
kobject_create_and_add的代码原型为:

struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
	参数
		name:新创建的内核对象的名称。
		parent:父内核对象的指针,可以是NULL,表示新对象是顶级对象。
	返回值
		成功时返回新创建的内核对象的指针。
		失败时返回错误指针(如 ERR_PTR)。

kobject_create_and_add函数中name字符串为创建的对象的名称对应节点/sys/(parent的路径)/(name字符串)
sysfs_create_group函数的grp参数内是一个或多个节点
代码示例,以下代码创建的节点位置为:/sys/lcm/lcm_name

/* add lcm_name*/
static struct kobject *k_obj = NULL;
static ssize_t show_lcm_name(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
{
	return sprintf(buf, "TD4160b-hy\n");
}

static struct kobj_attribute lcm_name_attribute = __ATTR(lcm_name, 0664, show_lcm_name, NULL);

static struct attribute *sysfs_lcm_attribute[] = {&lcm_name_attribute.attr, NULL};

static struct attribute_group sysfs_lcm_attr_group = {.attrs = sysfs_lcm_attribute,};
/* add lcm_name end*/

在lcm_probe函数内添加
/* add lcm_name node*/
if ((k_obj = kobject_create_and_add("lcm", NULL)) == NULL )
	{
		pr_err("lcm sys node create error\n");
	}
	if(sysfs_create_group(k_obj, &sysfs_lcm_attr_group) ) {
		pr_err("sysfs_create_group failed\n");
		kobject_put(k_obj);
	}
/* add lcm_name node end*/
在remove内添加
/* add lcm_name node*/
	if (k_obj) {
		sysfs_remove_group(k_obj, &sysfs_lcm_attr_group);
		kobject_put(k_obj);
	}
/* add lcm_name end*/

方案个人总结

如果创建节点位置任意,使用device_create_file创建,该函数创建需要device参数,常可以在驱动创建完成后直接创建节点,比较方便。当驱动remove时使用函数device_remove_file
如果指定了节点路径,并且节点较多,使用sysfs_create_group,当驱动remove时使用函数sysfs_remove_group
sysfs_create_group使用后
在remove内添加
/* add lcm_name node*/
	if (k_obj) {
		sysfs_remove_group(k_obj, &sysfs_lcm_attr_group);
		kobject_put(k_obj);
	}
/* add lcm_name end*/

文献引用

【1】MTK的TP信息节点创建:https://www.jianshu.com/p/11af0207231c(MTK平台-添加TP版本号节点(/sys/devices/platform/路径下添加节点))

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值