说在前面. 最近因为工作原因,天天在操作和调试led. 是时候写个总结啦.
在Android机中,一般都会把led设备的节点创建到/sys/class/leds下面. 创建节点的操作通常放在probe函数里面做.
这个时候需要做的包括:
- 定义一个struct drvdata(在.h文件中,或者在driver的c文件中都可以),并且在这个结构里面包含struct led_classdev abc_led;
struct drvdata {
struct led_classdev abc_led;
};
- 在probe函数中,声明一个1中的struct drvdata的指针变量drvdata_t,并且把这个变量和driver中的device绑定. 下面是对于i2c设备的操作,其他类型的设备操作类似.
drvdata_t = devm_kzalloc(&client->dev, sizeof(struct drvdata), GFP_KERNEL);
- 接着就是把这个结构下面的abc_led的成员给填好并且调用函数led_classdev_register.也就是在probe里面调用下面的函数,当然也可以直接在probe里面写函数内容,就是不太好看.
static int abc_led_register(struct device *dev, struct drvdata *data)
{
data->led.name = "abc_led";
data->led.brightness = LED_OFF;
data->led.max_brightness = LED_HALF;
data->led.default_trigger = "none";
data->led.brightness_set = abc_led_set;
data->led.brightness_get = abc_led_get;
return led_classdev_register(dev, &data->abc_led);
}
- 之后就是真的节点的注册了.en,要做好错误处理.
err = sysfs_create_group(&drvdata_t->led.dev->kobj, &abc_attr_group);
if (err)
goto xxx;
- 接着需要实现的是abc_attr_group结构;
static ssize_t led_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
//TODO: set gpio or send cmd to the device
return count;
}
static ssize_t led_on_show(struct device *dev, struct device_attribute *attr,char *buf)
{
//TODO: get gpio value or read from the cmd
return snprintf(buf, PAGE_SIZE,"%d\n", 0);
}
static DEVICE_ATTR(led_on, 0664, led_on_show, led_on_store);
static struct attribute *abc_attrs[] = {
&dev_attr_led_on.attr,
NULL
};
static const struct attribute_group abc_attr_group = {
.attrs = abc_attrs,
};
上面就可以创建出/sys/class/leds/abc_led/led_on节点了. 当然led_on_show和led_on_store要根据具体情况实现.
另外,需要在remove函数中进行unregister呀.
就是一个简短的小总结. 迈小步,不停步.