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