linux 光电模块,Linux内核LED模块分析

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。总算分析完了,还不明白就没办法了。^_^

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值