Chinaunix首页 | 论坛 | 博客
  • 博客访问: 819569
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2015-01-04 23:02:54

转:http://blog.csdn.net/z2007b/article/details/6369594

Linux内核LED模块分析(二)
上次分析到那里后,还是有些同志说看不懂,那我就继续分析一把我认为不需要继续分析的东西吧。上回分析

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;

 /* acts like an actual heart beat -- ie thump-thump-pause... */
 switch (heartbeat_data->phase) {
 case 0:
  /*
   * The hyperbolic function below modifies the
   * heartbeat period length in dependency of the
   * current (1min) load. It goes through the points
   * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
   */
  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。总算分析完了,还不明白就没办法了。^_^

阅读(1110) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~