Linux内核中ideapad-laptop.c文件全解析4

接上一篇文章《Linux内核中ideapad-laptop.c文件全解析3》,链接为:

Linux内核中ideapad-laptop.c文件全解析3_蓝天居士的博客-CSDN博客

上一回讲到了ideapad_sysfs_init函数由上到下的调用路线,本章我们来看具体内容。

再la来回顾一下调用栈,重点关注传入参数:

ideapad_sysfs_init

---> device_add_group(&priv->platform_device->dev, &ideapad_attribute_group)

---> sysfs_create_groups(&dev->kobj, groups);

---> internal_create_groups(kobj, 0, groups)

ideapad_attribute_group的定义在同文件(drivers/platform/x86/ideapad-laptop.c)中,代码如下:

static const struct attribute_group ideapad_attribute_group = {
	.is_visible = ideapad_is_visible,
	.attrs = ideapad_attributes
};

ideapad_attributes的定义在同文件中,代码如下:

static struct attribute *ideapad_attributes[] = {
	&dev_attr_camera_power.attr,
	&dev_attr_conservation_mode.attr,
	&dev_attr_fan_mode.attr,
	&dev_attr_fn_lock.attr,
	&dev_attr_touchpad.attr,
	&dev_attr_usb_charging.attr,
	NULL
};

 先来看一下ideapad_attributes指针数组中各个项的定义:

static DEVICE_ATTR_RW(camera_power);
static DEVICE_ATTR_RW(conservation_mode);
static DEVICE_ATTR_RW(fan_mode);
static DEVICE_ATTR_RW(fn_lock);
static DEVICE_ATTR_RW(touchpad);
static DEVICE_ATTR_RW(usb_charging);

DEVICE_ATTR_RW的定义在include/linux/device.h中:

#define DEVICE_ATTR_RW(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_RW(_name)

而__ATTR_RW的定义在include/linux/sysfs.h中:

#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)

__ATTR的定义在同文件中:

#define __ATTR(_name, _mode, _show, _store) {				\
	.attr = {.name = __stringify(_name),				\
		 .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },		\
	.show	= _show,						\
	.store	= _store,						\
}

综上,像数学公式般展开来,最终得到以下结果(以camera_power为例):

struct device_attribute dev_attr_camera_power = {
    .attr = {.name = "camera_power",
        .mode = 0644 },
    .show = camera_power_show,
    .store = camera_power_store,
}

其它几项也是同样的方法和形式,在这里就不一一展开了。
看一下各个项的实际内容:

  • camera_power
static ssize_t camera_power_show(struct device *dev,
				 struct device_attribute *attr,
				 char *buf)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	unsigned long result;
	int err;

	err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
	if (err)
		return err;

	return sysfs_emit(buf, "%d\n", !!result);
}

static ssize_t camera_power_store(struct device *dev,
				  struct device_attribute *attr,
				  const char *buf, size_t count)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	bool state;
	int err;

	err = kstrtobool(buf, &state);
	if (err)
		return err;

	err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
	if (err)
		return err;

	return count;
}

static DEVICE_ATTR_RW(camera_power);
  • conservation_mode
static ssize_t conservation_mode_show(struct device *dev,
				      struct device_attribute *attr,
				      char *buf)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	unsigned long result;
	int err;

	err = eval_gbmd(priv->adev->handle, &result);
	if (err)
		return err;

	return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result));
}

static ssize_t conservation_mode_store(struct device *dev,
				       struct device_attribute *attr,
				       const char *buf, size_t count)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	bool state;
	int err;

	err = kstrtobool(buf, &state);
	if (err)
		return err;

	err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF);
	if (err)
		return err;

	return count;
}

static DEVICE_ATTR_RW(conservation_mode);
  • fan_mode
static ssize_t fan_mode_show(struct device *dev,
			     struct device_attribute *attr,
			     char *buf)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	unsigned long result;
	int err;

	err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
	if (err)
		return err;

	return sysfs_emit(buf, "%lu\n", result);
}

static ssize_t fan_mode_store(struct device *dev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	unsigned int state;
	int err;

	err = kstrtouint(buf, 0, &state);
	if (err)
		return err;

	if (state > 4 || state == 3)
		return -EINVAL;

	err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
	if (err)
		return err;

	return count;
}

static DEVICE_ATTR_RW(fan_mode);
  • fn_lock
static ssize_t fn_lock_show(struct device *dev,
			    struct device_attribute *attr,
			    char *buf)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	unsigned long hals;
	int err;

	err = eval_hals(priv->adev->handle, &hals);
	if (err)
		return err;

	return sysfs_emit(buf, "%d\n", !!test_bit(HALS_FNLOCK_STATE_BIT, &hals));
}

static ssize_t fn_lock_store(struct device *dev,
			     struct device_attribute *attr,
			     const char *buf, size_t count)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	bool state;
	int err;

	err = kstrtobool(buf, &state);
	if (err)
		return err;

	err = exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
	if (err)
		return err;

	return count;
}

static DEVICE_ATTR_RW(fn_lock);
  • touchpad
static ssize_t touchpad_show(struct device *dev,
			     struct device_attribute *attr,
			     char *buf)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	unsigned long result;
	int err;

	err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
	if (err)
		return err;

	return sysfs_emit(buf, "%d\n", !!result);
}

static ssize_t touchpad_store(struct device *dev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	bool state;
	int err;

	err = kstrtobool(buf, &state);
	if (err)
		return err;

	err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
	if (err)
		return err;

	return count;
}

static DEVICE_ATTR_RW(touchpad);
  • usb_charging
static ssize_t usb_charging_show(struct device *dev,
				 struct device_attribute *attr,
				 char *buf)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	unsigned long hals;
	int err;

	err = eval_hals(priv->adev->handle, &hals);
	if (err)
		return err;

	return sysfs_emit(buf, "%d\n", !!test_bit(HALS_USB_CHARGING_STATE_BIT, &hals));
}

static ssize_t usb_charging_store(struct device *dev,
				  struct device_attribute *attr,
				  const char *buf, size_t count)
{
	struct ideapad_private *priv = dev_get_drvdata(dev);
	bool state;
	int err;

	err = kstrtobool(buf, &state);
	if (err)
		return err;

	err = exec_sals(priv->adev->handle, state ? SALS_USB_CHARGING_ON : SALS_USB_CHARGING_OFF);
	if (err)
		return err;

	return count;
}

static DEVICE_ATTR_RW(usb_charging);

可以看到,show和store函数中很多地方都调用了read_ec_data、write_ec_data等函数,也就是与笔记本EC(Embedded Controller)打交道的函数,这些函数我们单独用1-2个章节介绍。

至此,ideapad-laptop.c中sysfs部分的代码就已全部分析完了。

你可能感兴趣的:(Linux内核,Linux内核)