struct heartbeat_trig_data *heartbeat_data;
heartbeat_data =
kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
if (!heartbeat_data)
return;
led_cdev->trigger_data =
heartbeat_data;
setup_timer(&heartbeat_data->timer,
led_heartbeat_function, (unsigned long) led_cdev);
heartbeat_data->phase = 0;
led_heartbeat_function(heartbeat_data->timer.data);
}
很明显这里面最重要的东西就是初始化一个定时器然后调用led_heartbeat_function(),另外请注意定时器中定义的钩子函数也是这个。
static void led_heartbeat_function(unsigned long data)
{
struct led_classdev *led_cdev = (struct
led_classdev *) data;
struct heartbeat_trig_data *heartbeat_data =
led_cdev->trigger_data;
unsigned long brightness = LED_OFF;
unsigned long delay = 0;
switch (heartbeat_data->phase)
{
case 0:
heartbeat_data->period = 300
+
(6720
<< FSHIFT) / (5 * avenrun[0] + (7
<< FSHIFT));
heartbeat_data->period =
msecs_to_jiffies(heartbeat_data->period);
delay = msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness =
led_cdev->max_brightness;
break;
case 1:
delay = heartbeat_data->period /
4 - msecs_to_jiffies(70);
heartbeat_data->phase++;
break;
case 2:
delay = msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness =
led_cdev->max_brightness;
break;
default:
delay = heartbeat_data->period -
heartbeat_data->period / 4 -
msecs_to_jiffies(70);
heartbeat_data->phase = 0;
break;
}
led_set_brightness(led_cdev,
brightness);
mod_timer(&heartbeat_data->timer,
jiffies + delay);
}
我们又“避重就轻”的看到了这个函数最重要的一个两个函数:
led_set_brightness(led_cdev, brightness);
mod_timer(&heartbeat_data->timer,
jiffies + delay);
led_set_brightness(led_cdev,
brightness)这个函数从传入的参数看哥猜测是和led_cdev内核的成员函数相关的,前面我们一直先没有分析这个,所以跟起来有点麻烦,点进去一看,果不其然:
static inline void led_set_brightness(struct led_classdev
*led_cdev,
enum led_brightness value)
{
if (value >
led_cdev->max_brightness)
value =
led_cdev->max_brightness;
led_cdev->brightness =
value;
if (!(led_cdev->flags
& LED_SUSPENDED))
led_cdev->brightness_set(led_cdev, value);
}
是和led_cdev相关的,行,哥先忍着你,不理你。
mod_timer(&heartbeat_data->timer,
jiffies + delay);
这个就开始干活了,定时器一设定我们就开始干活罗。
我们之前一直绕过了一个东西那就是led_cdev这一块。
好我们找一找。哥在/drivers/leds中查找"heartbeat"。为什么要找这个呢?
还记得之前分析的地方:
if (!led_cdev->trigger
&&
led_cdev->default_trigger
&&
!strcmp(led_cdev->default_trigger,
trigger->name))
led_trigger_set(led_cdev,
trigger);
这里绑定的条件就是name。所以我们要以此为线索查找。
找了一下得到如下结果:
./leds-sunfire.c: .default_trigger= "heartbeat",
./leds-sunfire.c: .default_trigger= "heartbeat",
./ledtrig-heartbeat.c: .name = "heartbeat",
我们进入leds-sunfire.c中看一看。
static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
{
.name = "fhc-left",
.handler = fhc_left_set,
},
{
.name = "fhc-middle",
.handler = fhc_middle_set,
},
{
.name = "fhc-right",
.handler = fhc_right_set,
.default_trigger= "heartbeat",
},
};
找到一个这样的玩意。很明显是和led相关的,这时候哥有50%的把握这个文件中包含了我们想找的东西。快速浏览后哥就有100%的把握了。
platform_driver_register(&sunfire_fhc_led_driver);
这
是平台总线那个门派的东西,我们先不分析平台总线那一门派的技巧了,只告诉大家一个事,调用这个函数后sunfire_fhc_led_driver中的
probe成员函数将会被调用。(分析平台总线的文章很多,也不难,就算对这个不懂也不会影响我们的分析,只要记住我上面那句话就行了)
static struct platform_driver sunfire_fhc_led_driver = {
.probe =
sunfire_fhc_led_probe,
.remove =
__devexit_p(sunfire_led_generic_remove),
.driver = {
.name = "sunfire-fhc-leds",
.owner = THIS_MODULE,
},
};
static int __devinit sunfire_fhc_led_probe(struct platform_device
*pdev)
{
return sunfire_led_generic_probe(pdev,
fhc_led_types);
}
static int __devinit sunfire_led_generic_probe(struct
platform_device *pdev,
struct led_type *types)
{
struct sunfire_drvdata *p;
int i, err = -EINVAL;
if (pdev->num_resources != 1)
{
printk(KERN_ERR PFX "Wrong number of resources
%d, should be 1\n",
pdev->num_resources);
goto out;
}
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
printk(KERN_ERR PFX "Could not allocate struct
sunfire_drvdata\n");
goto out;
}
for (i = 0; i <
NUM_LEDS_PER_BOARD; i++) {
struct led_classdev *lp =
&p->leds[i].led_cdev;
p->leds[i].reg = (void __iomem
*) pdev->resource[0].start;
lp->name = types[i].name;
lp->brightness = LED_FULL;
lp->brightness_set =
types[i].handler;
lp->default_trigger =
types[i].default_trigger;
err =
led_classdev_register(&pdev->dev,
lp);
if (err) {
printk(KERN_ERR PFX "Could not
register %s LED\n",
lp->name);
goto
out_unregister_led_cdevs;
}
}
dev_set_drvdata(&pdev->dev,
p);
err = 0;
out:
return err;
out_unregister_led_cdevs:
for (i--; i >= 0; i--)
led_classdev_unregister(&p->leds[i].led_cdev);
goto out;
}
看到没有?
for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
struct led_classdev *lp =
&p->leds[i].led_cdev;
p->leds[i].reg = (void __iomem
*) pdev->resource[0].start;
lp->name = types[i].name;
lp->brightness = LED_FULL;
lp->brightness_set =
types[i].handler;
lp->default_trigger =
types[i].default_trigger;
err =
led_classdev_register(&pdev->dev,
lp);
if (err) {
printk(KERN_ERR PFX "Could not
register %s LED\n",
lp->name);
goto
out_unregister_led_cdevs;
}
}
这个函数:led_classdev_register(&pdev->dev,
lp)说是我们想要的东西。
int led_classdev_register(struct device *parent, struct
led_classdev *led_cdev)
{
led_cdev->dev =
device_create(leds_class, parent, 0, led_cdev,
"%s", led_cdev->name);
if (IS_ERR(led_cdev->dev))
return
PTR_ERR(led_cdev->dev);
#ifdef CONFIG_LEDS_TRIGGERS
init_rwsem(&led_cdev->trigger_lock);
#endif
down_write(&leds_list_lock);
list_add_tail(&led_cdev->node,
&leds_list);
up_write(&leds_list_lock);
if
(!led_cdev->max_brightness)
led_cdev->max_brightness =
LED_FULL;
led_update_brightness(led_cdev);
init_timer(&led_cdev->blink_timer);
led_cdev->blink_timer.function =
led_timer_function;
led_cdev->blink_timer.data =
(unsigned long)led_cdev;
#ifdef CONFIG_LEDS_TRIGGERS
led_trigger_set_default(led_cdev);
#endif
printk(KERN_DEBUG "Registered led device:
%s\n",
led_cdev->name);
return 0;
}
初始化,加入链表,初始化定时器,如果打开了CONFIG_LEDS_TRIGGERS这个宏,就调用led_trigger_set_default
。显然我们是打开了的,否则就不会有这篇文章了。
void led_trigger_set_default(struct led_classdev *led_cdev)
{
struct led_trigger *trig;
if
(!led_cdev->default_trigger)
return;
down_read(&triggers_list_lock);
down_write(&led_cdev->trigger_lock);
list_for_each_entry(trig,
&trigger_list, next_trig) {
if
(!strcmp(led_cdev->default_trigger,
trig->name))
led_trigger_set(led_cdev,
trig);
}
up_write(&led_cdev->trigger_lock);
up_read(&triggers_list_lock);
}
看到没有led_trigger_set(led_cdev, trig);
所以说,不管谁先来谁后来,都可以起到作用。
这就是内核是的lcd_dev和trigger的关系了。
谁先谁后都没关系的,大家是平等的,失去谁都不行。
OK,分析就到这里了。
继续分析一把我认为不需要继续分析的东西吧。上回分析了
led_cdev和trigger的关系后就没有继续说了。有同志还是没明白怎么调用的。干活的函数是:
static void led_heartbeat_function(unsigned long data)
{
struct led_classdev *led_cdev = (struct
led_classdev *) data;
struct heartbeat_trig_data *heartbeat_data =
led_cdev->trigger_data;
unsigned long brightness = LED_OFF;
unsigned long delay = 0;
switch (heartbeat_data->phase)
{
case 0:
heartbeat_data->period = 300
+
(6720
<< FSHIFT) / (5 * avenrun[0] + (7
<< FSHIFT));
heartbeat_data->period =
msecs_to_jiffies(heartbeat_data->period);
delay = msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness =
led_cdev->max_brightness;
break;
case 1:
delay = heartbeat_data->period /
4 - msecs_to_jiffies(70);
heartbeat_data->phase++;
break;
case 2:
delay = msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness =
led_cdev->max_brightness;
break;
default:
delay = heartbeat_data->period -
heartbeat_data->period / 4 -
msecs_to_jiffies(70);
heartbeat_data->phase = 0;
break;
}
led_set_brightness(led_cdev,
brightness);
mod_timer(&heartbeat_data->timer,
jiffies + delay);
}
这个函数里面调用了led_set_brightness(led_cdev, brightness);
static inline void led_set_brightness(struct led_classdev
*led_cdev,
enum led_brightness value)
{
if (value >
led_cdev->max_brightness)
value =
led_cdev->max_brightness;
led_cdev->brightness =
value;
if (!(led_cdev->flags
& LED_SUSPENDED))
led_cdev->brightness_set(led_cdev, value);
}
很明显这个函数调用了led_cdev->brightness_set(led_cdev,
value);
这个就是我们在leds-sunfire.c中注册的led_cdev。
我们回过头想一想我们刚开始注册led_cdev的过程:
static int __devinit sunfire_led_generic_probe(struct
platform_device *pdev,
struct led_type *types)
{
struct sunfire_drvdata *p;
int i, err = -EINVAL;
if (pdev->num_resources != 1)
{
printk(KERN_ERR PFX "Wrong number of resources
%d, should be 1\n",
pdev->num_resources);
goto out;
}
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
printk(KERN_ERR PFX "Could not allocate struct
sunfire_drvdata\n");
goto out;
}
for (i = 0; i <
NUM_LEDS_PER_BOARD; i++) {
struct led_classdev *lp =
&p->leds[i].led_cdev;
p->leds[i].reg = (void __iomem
*) pdev->resource[0].start;
lp->name = types[i].name;
lp->brightness = LED_FULL;
lp->brightness_set =
types[i].handler;
lp->default_trigger =
types[i].default_trigger;
err =
led_classdev_register(&pdev->dev,
lp);
if (err) {
printk(KERN_ERR PFX "Could not
register %s LED\n",
lp->name);
goto
out_unregister_led_cdevs;
}
}
dev_set_drvdata(&pdev->dev,
p);
err = 0;
out:
return err;
out_unregister_led_cdevs:
for (i--; i >= 0; i--)
led_classdev_unregister(&p->leds[i].led_cdev);
goto out;
}
看到了吧:
or (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
struct led_classdev *lp =
&p->leds[i].led_cdev;
p->leds[i].reg = (void __iomem
*) pdev->resource[0].start;
lp->name = types[i].name;
lp->brightness = LED_FULL;
lp->brightness_set =
types[i].handler;
lp->default_trigger =
types[i].default_trigger;
err =
led_classdev_register(&pdev->dev,
lp);
if (err) {
printk(KERN_ERR PFX "Could not
register %s LED\n",
lp->name);
goto
out_unregister_led_cdevs;
}
}
这时候就会将我们的handle函数挂在led_cdev的brightness_set。所以我们最终调用的是:
static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] =
{
{
.name =
"clockboard-left",
.handler = clockboard_left_set,
},
{
.name =
"clockboard-middle",
.handler = clockboard_middle_set,
},
{
.name =
"clockboard-right",
.handler = clockboard_right_set,
.default_trigger= "heartbeat",
},
};
这个结构体数组中第三个成员的handler函数。
也就是clockboard_right_set()。
static void clockboard_right_set(struct led_classdev
*led_cdev,
enum led_brightness led_val)
{
__clockboard_set(led_cdev, led_val,
CLOCK_CTRL_RLED);
}
static void __clockboard_set(struct led_classdev *led_cdev,
enum led_brightness led_val, u8 bit)
{
struct sunfire_led *p =
to_sunfire_led(led_cdev);
u8 reg = upa_readb(p->reg);
switch (bit) {
case CLOCK_CTRL_LLED:
if (led_val)
reg &=
~bit;
else
reg |= bit;
break;
default:
if (led_val)
reg |= bit;
else
reg &=
~bit;
break;
}
upa_writeb(reg, p->reg);
}
这个就是写寄存器了。OK。总算分析完了,还不明白就没办法了。^_^