接上一篇文章《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,
- }
其它几项也是同样的方法和形式,在这里就不一一展开了。
看一下各个项的实际内容:
- 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);
- 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);
- 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);
- 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);
- 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);
- 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部分的代码就已全部分析完了。