- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在做一个嵌入式项目。我们的主板使用的是 Linux 内核 v3.16.7。我正在努力支持几个监控事件的外围 LED。我已成功将启动程序修改为 load the drivers and create sysfs entries在 /sys/class/leds/
,这很棒。我还附上了 oneshot trigger到 LED 以便我可以 echo 1 > shot
从内部 /sys/class/leds/actled1\:green/
并且 LED 闪烁。正是我想要的。
但是,我想在启动期间实例化驱动程序时为每个 LED 配置延迟,但我不清楚如何做到这一点。驱动程序在 /sys/class/leds/actled1\:green/
中创建 sysfs 条目叫 delay_on
和 delay_off
,我可以从用户空间写入它们以配置延迟,但应该可以在实例化期间从内核空间设置它们的初始值。我也希望能够设置 invert
参数(这只是另一个 sysfs 条目,就像延迟一样)。
当我从内核空间实例化驱动程序时,如何配置 LED 触发器的参数?
下面是我如何实例化 LED GPIO。首先,我设置了所需的结构:
static struct gpio_led my_leds[] __initdata = {
{
.name = "actled1:green",
.default_trigger = "oneshot"
.gpio = ACTIVITY_LED_GPIO_BASE + 0,
.active_low = true,
},
{
.name = "actled2:red",
.default_trigger = "oneshot"
.gpio = ACTIVITY_LED_GPIO_BASE + 1,
.active_low = true,
},
};
static struct gpio_led_platform_data my_leds_pdata __initdata = {
.num_leds = ARRAY_SIZE(my_leds),
.leds = my_leds,
};
static int __init setup_my_leds (void)
{
struct platform_device *pdev;
int ret;
pdev = platform_device_alloc("leds-gpio", -1);
if (!pdev) {
return -ENOMEM;
}
ret = platform_device_add_data(pdev,
&my_leds_pdata,
sizeof(my_leds_pdata));
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
ret = platform_device_add(pdev);
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
return 0;
}
gpio_led
的定义结构在
include/linux/leds.h
line 327 ,以及
gpio_led_platform_data
的定义在
line 341 of the same file .
platform_device_add_data
的定义在
drivers/base/platform.c
line 284 .
drivers/leds/trigger/ledtrig-oneshot.c
) 以回答问题可能很有用。同样相关的是“leds-gpio”驱动程序(
drivers/leds/leds-gpio.c
)。
drivers/base/platform.c
中的某个地方和相关的
documentation ,但我没有看到任何处理我需要的数据的函数。
.ko
稍后使用 modprobe。 delay_on
/delay_off
.例如,oneshot 的 invert
范围。 最佳答案
有一些问题,我想我已经找到了解决方案,但是即使您提供了大量信息,也缺少一些东西,所以我会列举所有可能的情况,所以请耐心等待......
(1) 获取要设置的初始值。我想你已经想通了,但是......你可以从内核 cmdline 解析中得到这些(例如,你将值添加到/boot/grub2/grub.cfg 作为 myleds.delay_on=...
。如果你通过 modprobe
加载, 你设置了一个模块参数。这些也可以是一个配置文件,如 myleds.config_file=/etc/sysconfig/myleds.conf
(2) 您可以将它们设置在 setup_my_leds 中 [oneshot_trig_activate 的顽固性除外——我们很快就会处理]。来自 drivers/base/platform.c
:
/**
* arch_setup_pdev_archdata - Allow manipulation of archdata before its used
* @pdev: platform device
*
* This is called before platform_device_add() such that any pdev_archdata may
* be setup before the platform_notifier is called. So if a user needs to
* manipulate any relevant information in the pdev_archdata they can do:
*
* platform_device_alloc()
* ... manipulate ...
* platform_device_add()
*
* And if they don't care they can just call platform_device_register() and
* everything will just work out.
*/
static int __init setup_my_leds (void)
{
struct platform_device *pdev;
int ret;
// get initial values you want to set, possibly storing away for later use
my_leds_get_init_values(...);
pdev = platform_device_alloc("leds-gpio", -1);
if (!pdev) {
return -ENOMEM;
}
// Choice (1): set your initial values in my_leds_pdata here
my_leds_set_init_values(&my_leds_pdata);
// NOTE: just does kmemdup and sets pdev->dev.platform_data
ret = platform_device_add_data(pdev,
&my_leds_pdata,
sizeof(my_leds_pdata));
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
// Choice (2): set your initial values in pdev->dev.platform_data here
my_leds_set_init_values(pdev->dev.platform_data);
ret = platform_device_add(pdev);
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
return 0;
}
.default_trigger = "oneshot"
,以上数据会被
oneshot_trig_activate
炸掉在
drivers/leds/trigger/ledtrig-oneshot.c
.所以,我们需要解决这个问题。
oneshot_trig_activate
在
ledtrig-oneshot.c
并删除使用
DEFAULT_DELAY
的行.只有当您知道系统中可能需要默认值的其他任何东西都没有使用它时,这才真正有用。
ledtrig-oneshot.c
,但允许向
drivers/leds/trigger
添加新的触发器, 将文件复制到(例如)
ledtrig-oneshot2.c
并在那里进行更改。您需要更改
.name
至
.name = "oneshot2"
.简单的方法 [在 vi 中,当然 :-)] 是
:%s/oneshot/oneshot2/g
.为此,您还需要在 Kconfig 和 Makefile 中添加一个新条目。然后,更改结构定义以使用新驱动程序:
.default_trigger = "oneshot2"
drivers/leds/trigger
目录,复制
ledtrig-oneshot.c
到您的驱动程序目录[根据需要重命名]。从上面的选项 (B) 中进行编辑。在你的 Makefile 中使用一些技巧,你可以让它同时构建
my_led_driver.ko
和
ledtrig-oneshot2.ko
.你需要修改你的 Kconfig,可能添加一个
depends on LED_TRIGGERS
用于 LED 触发驱动器。您也可以将两者放在单独的子目录中,单独的 Makefile/Kconfig 可能更简单:
my_led/my_driver
和
my_led/my_trigger
my_leds_get_init_values
的注释是
possibly storing away for later use
.你可以换
oneshot2_trig_activate
调用它而不是使用
DEFAULT_DELAY
.我不太喜欢这个,更喜欢简单中性的解决方案
oneshot_trig_activate
的冒犯行为。但是,通过一些测试,您可能会发现您必须这样做。
drivers/led/trigger/ledtrig-oneshot.c
的替代品。 .
invert
参数不能直接通过您在设置函数中可以访问的任何标准结构[即它存储在触发器驱动程序内的私有(private)结构中],删除“选择(1)”和“选择(2)”。我们将在 [已修改]
oneshot_trig_activate
中一次性设置它们。 .
my_leds_get_init_values
设置并存储为全局变量。所以触发器驱动程序可以找到它们。也就是说,没有办法干净地执行此操作(例如,使用指向传递的私有(private)结构的指针),因为您在 setup 中有权访问的结构没有用于此的字段。有关此问题的讨论,请参阅触发器驱动程序的顶部。
diff -u
也可能有帮助。如果您拥有
git
下的所有信息,这样就更好了。
static
定义,因此不需要我之前建议的全局编辑。我确实做了
.name = "myled_oneshot";
,因此您需要将其与
.default_trigger = "myled_oneshot";
匹配.欢迎使用
my_leds_whatever
与您现有的命名约定保持一致。当我自己做这个时,我通常使用我的首字母,所以它变成了
ce_leds_whatever
--YMMV
/*
* One-shot LED Trigger
*
* Copyright 2012, Fabio Baltieri <fabio.baltieri@gmail.com>
*
* Based on ledtrig-timer.c by Richard Purdie <rpurdie@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/leds.h>
#include "../leds.h"
// C: we need to get access to the init data populated by the setup function
// we have the "clean way" with a struct definition inside a header file and
// the "dirty way" using three separate int globals
// in either case, the externs referenced here must be defined in the "my_leds"
// driver as global
// C: the "clean way"
// (1) requires that we have a path to the .h (e.g. -I<whatever)
// (2) this would be easier/preferable for the "Option (C)"
// (3) once done, easily extensible [probably not a consideration here]
#ifdef MYLED_USESTRUCT
#include "whatever/myled_init.h"
extern struct myled_init myled_init;
// C: the "ugly way"
// (1) no need to use a separate .h file
// (2) three separate global variables is wasteful
// (3) more than three, and we really should consider the "struct"
#else
extern int myled_init_delay_on;
extern int myled_init_delay_off;
extern int myled_init_invert;
#endif
#define DEFAULT_DELAY 100
// oneshot trigger driver private data
struct oneshot_trig_data {
unsigned int invert; // current invert state
};
// arm oneshot sequence from sysfs write to shot file
static ssize_t led_shot(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
led_blink_set_oneshot(led_cdev,
&led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
oneshot_data->invert);
/* content is ignored */
return size;
}
// show invert state for "cat invert"
static ssize_t led_invert_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
return sprintf(buf, "%u\n", oneshot_data->invert);
}
// set invert from sysfs write to invert file (e.g. echo 1 > invert)
static ssize_t led_invert_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
unsigned long state;
int ret;
ret = kstrtoul(buf, 0, &state);
if (ret)
return ret;
oneshot_data->invert = !!state;
if (oneshot_data->invert)
led_set_brightness_async(led_cdev, LED_FULL);
else
led_set_brightness_async(led_cdev, LED_OFF);
return size;
}
// show delay_on state for "cat delay_on"
static ssize_t led_delay_on_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
}
// set delay_on from sysfs write to delay_on file (e.g. echo 20 > delay_on)
static ssize_t led_delay_on_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;
int ret;
ret = kstrtoul(buf, 0, &state);
if (ret)
return ret;
led_cdev->blink_delay_on = state;
return size;
}
// show delay_off state for "cat delay_off"
static ssize_t led_delay_off_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
}
// set delay_off from sysfs write to delay_off file (e.g. echo 20 > delay_off)
static ssize_t led_delay_off_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;
int ret;
ret = kstrtoul(buf, 0, &state);
if (ret)
return ret;
led_cdev->blink_delay_off = state;
return size;
}
// these are the "attribute" definitions -- one for each sysfs entry
// pointers to these show up in the above functions as the "attr" argument
static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
static DEVICE_ATTR(shot, 0200, NULL, led_shot);
// activate the trigger device
static void oneshot_trig_activate(struct led_classdev *led_cdev)
{
struct oneshot_trig_data *oneshot_data;
int rc;
// create an instance of the private data we need
oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
if (!oneshot_data)
return;
// save the pointer in the led class struct so it's available to other
// functions above
led_cdev->trigger_data = oneshot_data;
// attach the sysfs entries
rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
if (rc)
goto err_out_trig_data;
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
if (rc)
goto err_out_delayon;
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
if (rc)
goto err_out_delayoff;
rc = device_create_file(led_cdev->dev, &dev_attr_shot);
if (rc)
goto err_out_invert;
// C: this is what the driver used to do
#if 0
led_cdev->blink_delay_on = DEFAULT_DELAY;
led_cdev->blink_delay_off = DEFAULT_DELAY;
#endif
led_cdev->activated = true;
// C: from here to the return is what the modified driver must do
#ifdef MYLED_USESTRUCT
led_cdev->blink_delay_on = myled_init.delay_on;
led_cdev->blink_delay_off = myled_init.delay_off;
oneshot_data->invert = myled_init.invert;
#else
led_cdev->blink_delay_on = myled_init_delay_on;
led_cdev->blink_delay_off = myled_init_delay_off;
oneshot_data->invert = myled_init_invert;
#endif
// C: if invert is off, nothing to do -- just like before
// if invert is set, we implement this as if we just got an instantaneous
// write to the sysfs "invert" file (which would call led_invert_store
// above)
// C: this is a direct rip-off of the above led_invert_store function which
// we can _not_ call here directly because we don't have access to the
// data it needs for its arguments [at least, not conveniently]
// so, we extract the one line we actually need
if (oneshot_data->invert)
led_set_brightness_async(led_cdev, LED_FULL);
return;
// release everything if an error occurs
err_out_invert:
device_remove_file(led_cdev->dev, &dev_attr_invert);
err_out_delayoff:
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
err_out_delayon:
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
err_out_trig_data:
kfree(led_cdev->trigger_data);
}
// deactivate the trigger device
static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
{
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
// release/destroy all the sysfs entries [and free the private data]
if (led_cdev->activated) {
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
device_remove_file(led_cdev->dev, &dev_attr_invert);
device_remove_file(led_cdev->dev, &dev_attr_shot);
kfree(oneshot_data);
led_cdev->activated = false;
}
/* Stop blinking */
led_set_brightness(led_cdev, LED_OFF);
}
// definition/control for trigger device registration
// C: changed the name to "myled_oneshot"
static struct led_trigger oneshot_led_trigger = {
.name = "myled_oneshot",
.activate = oneshot_trig_activate,
.deactivate = oneshot_trig_deactivate,
};
// module init function -- register the trigger device
static int __init oneshot_trig_init(void)
{
return led_trigger_register(&oneshot_led_trigger);
}
// module exit function -- unregister the trigger device
static void __exit oneshot_trig_exit(void)
{
led_trigger_unregister(&oneshot_led_trigger);
}
module_init(oneshot_trig_init);
module_exit(oneshot_trig_exit);
MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
MODULE_DESCRIPTION("One-shot LED trigger");
MODULE_LICENSE("GPL");
关于从内核空间配置 LED 触发器的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33310236/
嘿,我 wounderd 如果有什么。我可以继续阅读以改进此代码的突击队吗?至少它现在可以工作,但需要做一些微调:) 如您所见,代码非常困惑且难以阅读。希望有人能帮忙。 提前谢谢。 int potPi
我使用 AVR 作为微 Controller ,ATMEGA8 作为处理器(在微 Controller 内部)。带有微 Controller 的电路板有 4 个 LED。我能够刻录程序并点亮 LEDS
谁能解释一下两者之间的关系 LED 像素密度, LED像素高度和宽度 , 和 分辨率在创建模拟器时方法很详细。。并在启动时再次默认值:皮肤尺寸、密度;缩放密度以实现大小? 最佳答案 像素密度:每英寸像
我有一个由大小为 64*64 的 LED 组成的阵列。每个 LED 都可以点亮各种颜色,并且可以非常快速地改变颜色。我的最终目标是:对于网络摄像头接收到的每一帧,我希望能够从帧中“提取”LED 数组,
我正在使用 Arduino Uno 软件进行编码,但遇到了问题。我试图以随机顺序打开 8 个 LED,然后立即将它们全部关闭。我的问题是 LED 会多次点亮相同的 LED,但最终不会全部点亮。这使得电
当我使用Ethernet.begin(mac,ip)时,LED灯不会打开和关闭。但是当我不使用那条线时它就可以工作。但我需要使用以太网和 UPP 模块来打开和关闭。我怎样才能? 板卡型号:以太网08T
我试图顺时针和逆时针方向点亮我的 LED 灯。我使用mpu6050作为LED的方向控制。我检查了我的 mpu6050 驱动代码,它们没问题。顺时针方向工作时效果很好,所有 LED 灯均呈红色亮起。像这
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我是一名优秀的程序员,十分优秀!