接上一篇文章《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部分的代码就已全部分析完了。