1. Led class初始化
文件路径: \drivers\leds\led-class.c
static int __init leds_init(void)
{
leds_class = class_create(THIS_MODULE, "leds"); //生成目录/sys/class/leds
if (IS_ERR(leds_class))
return PTR_ERR(leds_class);
leds_class->pm = &leds_class_dev_pm_ops;
leds_class->dev_groups = led_groups; //子设备都具有这些属性
return 0;
}
在内核中搜索 leds_class
,可以看到被调用流程:
devm_led_classdev_register_ext
led_classdev_register_ext
device_create_with_groups(leds_class, parent, 0, led_cdev, led_cdev->groups, "%s", final_name);
2. 默认的属性文件attribute
在 leds_init
中可以看到,创建class时默认有属性文件:led_groups
static struct attribute *led_class_attrs[] = {
&dev_attr_brightness.attr,
&dev_attr_max_brightness.attr,
NULL,
};
static const struct attribute_group led_group = {
.attrs = led_class_attrs,
};
static const struct attribute_group *led_groups[] = {
&led_group,
#ifdef CONFIG_LEDS_TRIGGERS
&led_trigger_group,
#endif
NULL,
};
创建设备后,设备下就默认有brightness
、max_brightness
两个文件
设置亮度时 echo 255 > /sys/class/leds/xxx/brightness
就会调用到 brightness_store
函数:
static ssize_t brightness_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
unsigned long state;
ssize_t ret;
mutex_lock(&led_cdev->led_access);
if (led_sysfs_is_disabled(led_cdev)) {
ret = -EBUSY;
goto unlock;
}
ret = kstrtoul(buf, 10, &state);
if (ret)
goto unlock;
if (state == LED_OFF)
led_trigger_remove(led_cdev);
led_set_brightness(led_cdev, state);
flush_work(&led_cdev->set_brightness_work);
ret = size;
unlock:
mutex_unlock(&led_cdev->led_access);
return ret;
}
最终会调用 led_cdev->brightness_set(led_cdev, value);
3. struct led_classdev
led_classdev_register_ext
函数需要一个led_classdev 结构体作为参数,led_classdev
是核心,
驱动程序需要申请,配置,注册这个led_classdev,先看一下这个结构体:
struct led_classdev {
const char *name;
const char *default_trigger;
enum led_brightness brightness; //亮度
struct device *dev; //记录在类下面创建设备时返回的device,由device_create_with_groups()返回
const struct attribute_group **groups; //创建device时传入,对应/sys/class/leds/.../下的属性文件
...
/* 使用之前需要初始化这些函数 */
void (*brightness_set)(struct led_classdev *led_cdev, enum led_brightness brightness);//Set LED brightness level
int (*brightness_set_blocking)(struct led_classdev *led_cdev,enum led_brightness brightness);
...
};
4. Leds-gpio驱动
搜索devm_led_classdev_register_ext
函数,调用该函数在leds_class 下注册设备的地方应该就是我们要找的led驱动程序了.
以leds-gpio驱动程序为例:\drivers\leds\led-class.c
int gpio_led_probe(struct platform_device *pdev)
struct gpio_leds_priv *priv = gpio_leds_create(pdev); //子函数中申请gpio_leds_priv
| create_gpio_led(&led, led_dat, dev, child, NULL); //配置led_classdev结构体
| | devm_led_classdev_register_ext(parent, &led_dat->cdev, &init_data);
platform_set_drvdata(pdev, priv);