Android模拟器学framework和driver之battery & backlight-----5. backlight in linux .

前面介绍了battery的相关的东西,现在我们来介绍下backlight模块,背光主要是用来调节显示屏亮度的,一般背光都是用PWM控制的,调节占空比达到改变有效电压值来调节光的强弱。

背光的移植在linux中虽然不是那么难,但是背光这个组件对我们嵌入式设备的续航能力有很大的影响,一般背光上面加的电压会有20多的电压,所以这部分会很耗电的,相当于是开了个大灯泡。

现在我们先来看下android goldfish中的背光代码,哈哈,没找到吧,没有,我们打开模拟器,看sysfs中,也是没有具体的背光的文件的,所以这里我们得自己实现,自己写代码练习练习,毕竟这部分不是非常的难,参考drivers/video/backlight/下的pwm_bl.c文件,基本可以仿照,我们要做的事情很简单,创建背光相关的文件系统即可,不需要去控制硬件做什么动作,因为我们本来就没有硬件。

首先看下video中的makefile,如果backlight/没有选中就选中它,不然我们的模块不会编译进去。然后再看下backlight/下的Makefile

  1. obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o  
  2. obj-$(CONFIG_LCD_CORGI)            += corgi_lcd.o  
  3. obj-$(CONFIG_LCD_LTV350QV)         += ltv350qv.o  
  4. obj-$(CONFIG_LCD_ILI9320)          += ili9320.o  
  5. obj-$(CONFIG_LCD_PLATFORM)         += platform_lcd.o  
  6. obj-$(CONFIG_LCD_VGG2432A4)        += vgg2432a4.o  
  7. obj-$(CONFIG_LCD_TDO24M)           += tdo24m.o  
  8. obj-$(CONFIG_LCD_TOSA)             += tosa_lcd.o  
  9.   
  10. obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o  
  11. obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o  
  12. obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o  
  13. obj-$(CONFIG_BACKLIGHT_HP680)   += hp680_bl.o  
  14. obj-$(CONFIG_BACKLIGHT_LOCOMO)  += locomolcd.o  
  15. obj-$(CONFIG_BACKLIGHT_OMAP1)   += omap1_bl.o  
  16. obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o  
  17. obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o  
  18. obj-$(CONFIG_BACKLIGHT_PWM)     += pwm_bl.o  
  19. obj-$(CONFIG_BACKLIGHT_DA903X)  += da903x_bl.o  
  20. obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o  
  21. obj-$(CONFIG_BACKLIGHT_TOSA)    += tosa_bl.o  
  22. obj-$(CONFIG_BACKLIGHT_SAHARA)  += kb3886_bl.o  
obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
obj-$(CONFIG_LCD_CORGI)            += corgi_lcd.o
obj-$(CONFIG_LCD_LTV350QV)         += ltv350qv.o
obj-$(CONFIG_LCD_ILI9320)          += ili9320.o
obj-$(CONFIG_LCD_PLATFORM)         += platform_lcd.o
obj-$(CONFIG_LCD_VGG2432A4)        += vgg2432a4.o
obj-$(CONFIG_LCD_TDO24M)           += tdo24m.o
obj-$(CONFIG_LCD_TOSA)             += tosa_lcd.o

obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o
obj-$(CONFIG_BACKLIGHT_HP680)   += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO)  += locomolcd.o
obj-$(CONFIG_BACKLIGHT_OMAP1)   += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
obj-$(CONFIG_BACKLIGHT_PWM)     += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X)  += da903x_bl.o
obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
obj-$(CONFIG_BACKLIGHT_TOSA)    += tosa_bl.o
obj-$(CONFIG_BACKLIGHT_SAHARA)  += kb3886_bl.o

这里没有一个文件被编译进去的,我们要把backlight.c先编译进去,直接这样改,我比较懒 呵呵呵,

  1. obj-y += backlight.o  
  2. obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o  
obj-y += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
然后重新编译下会生成backlight.o文件,并且在sysfs中会生成我们的backlight class

我们先来分析下backlight.c中的代码是如何实现的。

养成好习惯,看见代码多不用怕,首先看init函数:

  1. static int __init backlight_class_init(void)  
  2. {  
  3.     backlight_class = class_create(THIS_MODULE, "backlight");  
  4.     if (IS_ERR(backlight_class)) {  
  5.         printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",  
  6.                 PTR_ERR(backlight_class));  
  7.         return PTR_ERR(backlight_class);  
  8.     }  
  9.   
  10.     backlight_class->dev_attrs = bl_device_attributes;  
  11.     backlight_class->suspend = backlight_suspend;  
  12.     backlight_class->resume = backlight_resume;  
  13.     return 0;  
  14. }  
  15.   
  16. /* 
  17.  * if this is compiled into the kernel, we need to ensure that the 
  18.  * class is registered before users of the class try to register lcd's 
  19.  */  
  20. postcore_initcall(backlight_class_init);  
static int __init backlight_class_init(void)
{
	backlight_class = class_create(THIS_MODULE, "backlight");
	if (IS_ERR(backlight_class)) {
		printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
				PTR_ERR(backlight_class));
		return PTR_ERR(backlight_class);
	}

	backlight_class->dev_attrs = bl_device_attributes;
	backlight_class->suspend = backlight_suspend;
	backlight_class->resume = backlight_resume;
	return 0;
}

/*
 * if this is compiled into the kernel, we need to ensure that the
 * class is registered before users of the class try to register lcd's
 */
postcore_initcall(backlight_class_init);

很简单,这里只是用了class_create函数在sys/class下创建了backlight文件夹,然后是
backlight_class->dev_attrs = bl_device_attributes;
在backlight class中创建了一系列的文件系统,

  1. <pre name="code" class="cpp">static ssize_t backlight_show_power(struct device *dev,  
  2.         struct device_attribute *attr,char *buf)  
  3. {  
  4.     struct backlight_device *bd = to_backlight_device(dev);  
  5.   
  6.     return sprintf(buf, "%d\n", bd->props.power);  
  7. }  
  8.   
  9. static ssize_t backlight_store_power(struct device *dev,  
  10.         struct device_attribute *attr, const char *buf, size_t count)  
  11. {  
  12.     int rc;  
  13.     struct backlight_device *bd = to_backlight_device(dev);  
  14.     unsigned long power;  
  15.   
  16.     rc = strict_strtoul(buf, 0, &power);  
  17.     if (rc)  
  18.         return rc;  
  19.   
  20.     rc = -ENXIO;  
  21.     mutex_lock(&bd->ops_lock);  
  22.     if (bd->ops) {  
  23.         pr_debug("backlight: set power to %lu\n", power);  
  24.         if (bd->props.power != power) {  
  25.             bd->props.power = power;  
  26.             backlight_update_status(bd);  
  27.         }  
  28.         rc = count;  
  29.     }  
  30.     mutex_unlock(&bd->ops_lock);  
  31.   
  32.     return rc;  
  33. }  
<pre name="code" class="cpp">static ssize_t backlight_show_power(struct device *dev,
		struct device_attribute *attr,char *buf)
{
	struct backlight_device *bd = to_backlight_device(dev);

	return sprintf(buf, "%d\n", bd->props.power);
}

static ssize_t backlight_store_power(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int rc;
	struct backlight_device *bd = to_backlight_device(dev);
	unsigned long power;

	rc = strict_strtoul(buf, 0, &power);
	if (rc)
		return rc;

	rc = -ENXIO;
	mutex_lock(&bd->ops_lock);
	if (bd->ops) {
		pr_debug("backlight: set power to %lu\n", power);
		if (bd->props.power != power) {
			bd->props.power = power;
			backlight_update_status(bd);
		}
		rc = count;
	}
	mutex_unlock(&bd->ops_lock);

	return rc;
}

所以我们的驱动只要填充好具体的结构体,初始化好文件系统就够了,在sysfs中生成可以让user space调用的接口,接下来的事情就交给上层开发人员去做。

ok,我们来看下我们自己写的驱动,在backlight文件夹下新建一个文件叫  android-backlight.c,我是参照pwm_bl.c来写的,具体先来看下代码,init函数

  1. static int __init android_backlight_init(void)  
  2. {  
  3.     return platform_driver_register(&android_backlight_driver);  
  4. }  
  5.   
  6. static void __exit android_backlight_exit(void)  
  7. {  
  8.     platform_driver_unregister(&android_backlight_driver);  
  9. }  
  10.   
  11. module_init(android_backlight_init);  
  12. module_exit(android_backlight_exit);  
static int __init android_backlight_init(void)
{
	return platform_driver_register(&android_backlight_driver);
}

static void __exit android_backlight_exit(void)
{
	platform_driver_unregister(&android_backlight_driver);
}

module_init(android_backlight_init);
module_exit(android_backlight_exit);

使用platform_driver_register注册平台驱动,看下传入的参数:

  1. static struct platform_driver android_backlight_driver = {  
  2.     .driver ={  
  3.         .name = "android-backlight",  
  4.         .owner = THIS_MODULE,  
  5.     },  
  6.     .probe  =   android_backlight_probe,  
  7. //  .remove =   ........   
  8. //  .suspend   
  9. //  .resume   
  10.   
  11.   
  12. };  
static struct platform_driver android_backlight_driver = {
	.driver	={
		.name = "android-backlight",
		.owner = THIS_MODULE,
	},
	.probe	=	android_backlight_probe,
//	.remove	=	........
//	.suspend
//	.resume


};

这里我偷懒没写remove suspend和resume'回调函数,在移植具体驱动的时候我们都应该写上,特别是suspend和resume函数,来看下我们paltform驱动的device_register是在哪做的,在arch/arm/mach-goldfish/board-goldfish.c

  1. struct platform_device android_backlight_device = {  
  2.     .name = "android-backlight",  
  3.     .id = 0,  
  4. };  
  5.   
  6. static struct platform_pwm_backlight_data android_backlight_data = {  
  7.     .pwm_id = 0,  
  8.     .max_brightness = 255,  
  9.     .dft_brightness = 128,  
  10. //  .pwm_period_ns = ...;   
  11. };  
struct platform_device android_backlight_device = {
	.name = "android-backlight",
	.id = 0,
};

static struct platform_pwm_backlight_data android_backlight_data = {
	.pwm_id = 0,
	.max_brightness = 255,
	.dft_brightness = 128,
//	.pwm_period_ns = ...;
};

在init中进行注册:

  1. static void __init goldfish_init(void)  
  2. {  
  3.     platform_device_register(&goldfish_pdev_bus_device);  
  4.     platform_device_register(&android_light_device);  
  5.     platform_device_register(&android_switch_device);  
  6.     platform_device_register(&vh_device);  
  7.     platform_device_register(&android_temperature_device);  
  8.     <SPAN style="COLOR: #ff0000">android_register_device(&android_backlight_device, &android_backlight_data);</SPAN>  
  9. }  
static void __init goldfish_init(void)
{
	platform_device_register(&goldfish_pdev_bus_device);
	platform_device_register(&android_light_device);
	platform_device_register(&android_switch_device);
	platform_device_register(&vh_device);
	platform_device_register(&android_temperature_device);
	android_register_device(&android_backlight_device, &android_backlight_data);
}

这边android_backlight_data结构体主要是做一个背光的初始化。

接下来我们看一下probe函数,

  1. static int android_backlight_probe(struct platform_device *pdev)  
  2. {  
  3.     //pass the struct from board-goldfish.c ----> init platform data   
  4.     struct platform_pwm_backlight_data *data=pdev->dev.platform_data;  
  5.     //local private struct   
  6.     struct android_pwm_data *pd;  
  7.     //backlight properties struct----> defined in include/linux/backlight.h   
  8.   
  9.     struct backlight_properties props;  
  10.     struct backlight_device *bl;    //struct infomation defined in include/linux/backlight.h   
  11.   
  12.     int ret;  
  13.   
  14.     if (!data) {  
  15.         dev_err(&pdev->dev, "failed to find platform data\n");  
  16.         return -EINVAL;  
  17.     }  
  18.     //----for here we haven't set init pointer function...   
  19.     if(data->init)  
  20.     {  
  21.         ret=data->init(&pdev->dev);  
  22.         if(ret<0)  
  23.             return ret;  
  24.     }  
  25.       
  26.     pd = kzalloc(sizeof(*pd),GFP_KERNEL);  
  27.     if(!pd)  
  28.     {  
  29.         dev_err(&pdev->dev, "no memory for state\n");  
  30.         ret = -ENOMEM;  
  31.         goto err_alloc;  
  32.     }  
  33.   
  34. //  pd->period = data->pwm_period_ns;   
  35.     pd->notify = data->notify;  
  36.     pd->dev = &pdev->dev;  
  37.   
  38. /*  pd->pwm = pwm_request(data->pwm_id, "backlight"); 
  39.     if (IS_ERR(pb->pwm)) { 
  40.         dev_err(&pdev->dev, "unable to request PWM for backlight\n"); 
  41.         ret = PTR_ERR(pb->pwm); 
  42.         goto err_pwm; 
  43.     } else 
  44.         dev_dbg(&pdev->dev, "got pwm for backlight\n"); 
  45. */  
  46.     memset(&props,0,sizeof(struct backlight_properties));  
  47.     bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pd,&android_backlight_ops);  
  48.     if (IS_ERR(bl)) {  
  49.         dev_err(&pdev->dev, "failed to register backlight\n");  
  50.         ret = PTR_ERR(bl);  
  51. //      goto err_bl;   
  52.     }  
  53.     bl->props.max_brightness = data->max_brightness;  
  54.   
  55.     bl->props.brightness=data->dft_brightness;  
  56.   
  57.     platform_set_drvdata(pdev,bl);  
  58.   
  59. //err_bl:   
  60. //  pwm_free(pd->pwm);   
  61. //err_pwm:   
  62. //  kfree(pb);   
  63. err_alloc:  
  64.     if (data->exit)  
  65.         data->exit(&pdev->dev);  
  66.     return ret;  
  67. }  
static int android_backlight_probe(struct platform_device *pdev)
{
	//pass the struct from board-goldfish.c ----> init platform data
	struct platform_pwm_backlight_data *data=pdev->dev.platform_data;
	//local private struct
	struct android_pwm_data *pd;
	//backlight properties struct----> defined in include/linux/backlight.h

	struct backlight_properties props;
	struct backlight_device *bl;	//struct infomation defined in include/linux/backlight.h

	int ret;

	if (!data) {
		dev_err(&pdev->dev, "failed to find platform data\n");
		return -EINVAL;
	}
	//----for here we haven't set init pointer function...
	if(data->init)
	{
		ret=data->init(&pdev->dev);
		if(ret<0)
			return ret;
	}
	
	pd = kzalloc(sizeof(*pd),GFP_KERNEL);
	if(!pd)
	{
		dev_err(&pdev->dev, "no memory for state\n");
		ret = -ENOMEM;
		goto err_alloc;
	}

//	pd->period = data->pwm_period_ns;
	pd->notify = data->notify;
	pd->dev = &pdev->dev;

/*	pd->pwm = pwm_request(data->pwm_id, "backlight");
	if (IS_ERR(pb->pwm)) {
		dev_err(&pdev->dev, "unable to request PWM for backlight\n");
		ret = PTR_ERR(pb->pwm);
		goto err_pwm;
	} else
		dev_dbg(&pdev->dev, "got pwm for backlight\n");
*/
	memset(&props,0,sizeof(struct backlight_properties));
	bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pd,&android_backlight_ops);
	if (IS_ERR(bl)) {
		dev_err(&pdev->dev, "failed to register backlight\n");
		ret = PTR_ERR(bl);
//		goto err_bl;
	}
	bl->props.max_brightness = data->max_brightness;

	bl->props.brightness=data->dft_brightness;

	platform_set_drvdata(pdev,bl);

//err_bl:
//	pwm_free(pd->pwm);
//err_pwm:
//	kfree(pb);
err_alloc:
	if (data->exit)
		data->exit(&pdev->dev);
	return ret;
}

首先检查我们得到的platform_data结构体中有没有init回调函数,有的话执行,没有的话跳过。

  1. if(data->init)  
  2. {  
  3.     ret=data->init(&pdev->dev);  
  4.     if(ret<0)  
  5.         return ret;  
  6. }  
	if(data->init)
	{
		ret=data->init(&pdev->dev);
		if(ret<0)
			return ret;
	}

这边比较重要的是backlight_device_register函数

  1. struct backlight_device *backlight_device_register(const char *name,  
  2.         struct device *parent, void *devdata, struct backlight_ops *ops)  
  3. {  
  4.     struct backlight_device *new_bd;  
  5.     int rc;  
  6.   
  7.     pr_debug("backlight_device_register: name=%s\n", name);  
  8.   
  9.     new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);  
  10.     if (!new_bd)  
  11.         return ERR_PTR(-ENOMEM);  
  12.   
  13.     mutex_init(&new_bd->update_lock);  
  14.     mutex_init(&new_bd->ops_lock);  
  15.   
  16.     new_bd->dev.class = backlight_class;  
  17.     new_bd->dev.parent = parent;  
  18.     new_bd->dev.release = bl_device_release;  
  19.     dev_set_name(&new_bd->dev, name);  
  20.     dev_set_drvdata(&new_bd->dev, devdata);  
  21.   
  22.     rc = device_register(&new_bd->dev);  
  23.     if (rc) {  
  24.         kfree(new_bd);  
  25.         return ERR_PTR(rc);  
  26.     }  
  27.   
  28.     rc = backlight_register_fb(new_bd);  
  29.     if (rc) {  
  30.         device_unregister(&new_bd->dev);  
  31.         return ERR_PTR(rc);  
  32.     }  
  33.   
  34.     new_bd->ops = ops;  
  35.   
  36. #ifdef CONFIG_PMAC_BACKLIGHT   
  37.     mutex_lock(&pmac_backlight_mutex);  
  38.     if (!pmac_backlight)  
  39.         pmac_backlight = new_bd;  
  40.     mutex_unlock(&pmac_backlight_mutex);  
  41. #endif   
  42.   
  43.     return new_bd;  
  44. }  
  45. EXPORT_SYMBOL(backlight_device_register);  
struct backlight_device *backlight_device_register(const char *name,
		struct device *parent, void *devdata, struct backlight_ops *ops)
{
	struct backlight_device *new_bd;
	int rc;

	pr_debug("backlight_device_register: name=%s\n", name);

	new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
	if (!new_bd)
		return ERR_PTR(-ENOMEM);

	mutex_init(&new_bd->update_lock);
	mutex_init(&new_bd->ops_lock);

	new_bd->dev.class = backlight_class;
	new_bd->dev.parent = parent;
	new_bd->dev.release = bl_device_release;
	dev_set_name(&new_bd->dev, name);
	dev_set_drvdata(&new_bd->dev, devdata);

	rc = device_register(&new_bd->dev);
	if (rc) {
		kfree(new_bd);
		return ERR_PTR(rc);
	}

	rc = backlight_register_fb(new_bd);
	if (rc) {
		device_unregister(&new_bd->dev);
		return ERR_PTR(rc);
	}

	new_bd->ops = ops;

#ifdef CONFIG_PMAC_BACKLIGHT
	mutex_lock(&pmac_backlight_mutex);
	if (!pmac_backlight)
		pmac_backlight = new_bd;
	mutex_unlock(&pmac_backlight_mutex);
#endif

	return new_bd;
}
EXPORT_SYMBOL(backlight_device_register);

这里做的最主要的事情就是对一些结构体的初始化,然后调用device_register把我们具体的device挂到我们的backlight class下,具体的是如何实现的我这里不多说,我这里只做一些简单的介绍。这里大家可以看到最重要的是backlight_device_register函数的最后一个参数,这里提供了我们可以自己定义的几个回调函数,

  1. struct backlight_ops {  
  2.     unsigned int options;  
  3.   
  4. #define BL_CORE_SUSPENDRESUME   (1 << 0)   
  5.   
  6.     /* Notify the backlight driver some property has changed */  
  7.     int (*update_status)(struct backlight_device *);  
  8.     /* Return the current backlight brightness (accounting for power, 
  9.        fb_blank etc.) */  
  10.     int (*get_brightness)(struct backlight_device *);  
  11.     /* Check if given framebuffer device is the one bound to this backlight; 
  12.        return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */  
  13.     int (*check_fb)(struct fb_info *);  
  14. };  
struct backlight_ops {
	unsigned int options;

#define BL_CORE_SUSPENDRESUME	(1 << 0)

	/* Notify the backlight driver some property has changed */
	int (*update_status)(struct backlight_device *);
	/* Return the current backlight brightness (accounting for power,
	   fb_blank etc.) */
	int (*get_brightness)(struct backlight_device *);
	/* Check if given framebuffer device is the one bound to this backlight;
	   return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */
	int (*check_fb)(struct fb_info *);
};

我们这边定义了2个回调函数挂上去:

  1. static const struct backlight_ops android_backlight_ops = {  
  2.     .update_status  = android_backlight_update_status,  
  3.     .get_brightness = android_backlight_get_brightness,  
  4. //        .check_fb...     
  5. };  
static const struct backlight_ops android_backlight_ops = {
	.update_status  = android_backlight_update_status,
	.get_brightness = android_backlight_get_brightness,
//        .check_fb...	
};

然后我们去实现这2个函数,就基本完成了我们的驱动了,看函数名字就知道这2个函数的作用,一个是用来更新我们的背光亮度,还有一个是用来得到我们的光强。

  1. static int android_backlight_get_brightness(struct backlight_device *bl)  
  2. {  
  3.     printk(KERN_INFO "[android]---get brightness...\n");  
  4.     return bl->props.brightness;  
  5. }  
static int android_backlight_get_brightness(struct backlight_device *bl)
{
	printk(KERN_INFO "[android]---get brightness...\n");
	return bl->props.brightness;
}

这个函数比较简单,就是返回backlight_device->props->brightness,我们来看下最终我们的brightness是哪里写进去的。这里比较绕,我们还是结合update函数一起分析:

  1. static int android_backlight_update_status(struct backlight_device *bl)  
  2. {  
  3.     struct android_pwm_data *pd = dev_get_drvdata(&bl->dev);  
  4.     int brightness = bl->props.brightness;  
  5.     int max=bl->props.max_brightness;  
  6.   
  7. /*  if (bl->props.power != FB_BLANK_UNBLANK) 
  8.         brightness = 0; 
  9.  
  10.     if (bl->props.fb_blank != FB_BLANK_UNBLANK) 
  11.         brightness = 0; 
  12. */  
  13.     printk(KERN_INFO "update brightness...\n");  
  14.     if (pd->notify)  
  15.         brightness = pd->notify(pd->dev, brightness);  
  16.     //+++add   
  17.     global_brightness = brightness;  
  18. //  complete(&priv_event);   
  19.     printk(KERN_INFO "complete event....\n");  
  20.     return 0;  
  21. }  
static int android_backlight_update_status(struct backlight_device *bl)
{
	struct android_pwm_data *pd = dev_get_drvdata(&bl->dev);
	int brightness = bl->props.brightness;
	int max=bl->props.max_brightness;

/*	if (bl->props.power != FB_BLANK_UNBLANK)
		brightness = 0;

	if (bl->props.fb_blank != FB_BLANK_UNBLANK)
		brightness = 0;
*/
	printk(KERN_INFO "update brightness...\n");
	if (pd->notify)
		brightness = pd->notify(pd->dev, brightness);
	//+++add
	global_brightness = brightness;
//	complete(&priv_event);
	printk(KERN_INFO "complete event....\n");
	return 0;
}

我们姑且这么理解,我们有一个结构体,brightness_properity用来存放backlight的一些属性信息,比如说brightness,当我们要get_brightness的时候就是去返回这个brightness,当我们要调节光强的时候就是给这个结构体中的成员变量赋值。

首先我们要了解android中用户层是怎么做的,因为我们linux driver最终的目标就是服务用户层,所以我们要了解。

其实android HAL层就是open backlight中的brightness这个节点,然后进行读写来设置背光的亮度的,好吧,先来看下读写这个节点会呼叫的回调函数

在backlight.c中实现:

  1. static ssize_t backlight_show_brightness(struct device *dev,  
  2.         struct device_attribute *attr, char *buf)  
  3. {  
  4.     struct backlight_device *bd = to_backlight_device(dev);  
  5.   
  6.     return sprintf(buf, "%d\n", bd->props.brightness);  
  7. }  
  8.   
  9. static ssize_t backlight_store_brightness(struct device *dev,  
  10.         struct device_attribute *attr, const char *buf, size_t count)  
  11. {  
  12.     int rc;  
  13.     struct backlight_device *bd = to_backlight_device(dev);  
  14.     unsigned long brightness;  
  15.   
  16.     rc = strict_strtoul(buf, 0, &brightness);  
  17.     if (rc)  
  18.         return rc;  
  19.   
  20.     rc = -ENXIO;  
  21.   
  22.     mutex_lock(&bd->ops_lock);  
  23.     if (bd->ops) {  
  24.         if (brightness > bd->props.max_brightness)  
  25.             rc = -EINVAL;  
  26.         else {  
  27.             pr_debug("backlight: set brightness to %lu\n",  
  28.                  brightness);  
  29.             bd->props.brightness = brightness;  
  30.             backlight_update_status(bd);  
  31.             rc = count;  
  32.         }  
  33.     }  
  34.     mutex_unlock(&bd->ops_lock);  
  35.   
  36.     return rc;  
  37. }  
static ssize_t backlight_show_brightness(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct backlight_device *bd = to_backlight_device(dev);

	return sprintf(buf, "%d\n", bd->props.brightness);
}

static ssize_t backlight_store_brightness(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int rc;
	struct backlight_device *bd = to_backlight_device(dev);
	unsigned long brightness;

	rc = strict_strtoul(buf, 0, &brightness);
	if (rc)
		return rc;

	rc = -ENXIO;

	mutex_lock(&bd->ops_lock);
	if (bd->ops) {
		if (brightness > bd->props.max_brightness)
			rc = -EINVAL;
		else {
			pr_debug("backlight: set brightness to %lu\n",
				 brightness);
			bd->props.brightness = brightness;
			backlight_update_status(bd);
			rc = count;
		}
	}
	mutex_unlock(&bd->ops_lock);

	return rc;
}

当我们向brightness这个文件节点中写入我们要设置的背光亮度的时候会调用store这个回调函数,我们来看下主要做了哪些事情,跟我们在driver层自己写的update函数到底有什么关系呢?

前面都是一大堆不用看的代码,这里最重要的看这个

  1.     if (bd->ops) {  
  2.         if (brightness > bd->props.max_brightness)  
  3.             rc = -EINVAL;  
  4.         else {  
  5.             pr_debug("backlight: set brightness to %lu\n",  
  6.                  brightness);  
  7. <SPAN style="COLOR: #ff0000">           bd->props.brightness = brightness;  
  8.             backlight_update_status(bd);</SPAN>  
  9.             rc = count;  
  10.         }  
  11.     }  
	if (bd->ops) {
		if (brightness > bd->props.max_brightness)
			rc = -EINVAL;
		else {
			pr_debug("backlight: set brightness to %lu\n",
				 brightness);
			bd->props.brightness = brightness;
			backlight_update_status(bd);
			rc = count;
		}
	}

首先是把brightness写进我们的背光属性结构体中,这样就更新了我们数据结构中的背光亮度在值,但是这样做是不够的,因为我们最终要控制的是硬件,所以看下之后我们调用了backlight_update_status函数,ok,看下这个函数的定义:

/include/linux/backlight.h

  1. static inline void backlight_update_status(struct backlight_device *bd)  
  2. {  
  3.     mutex_lock(&bd->update_lock);  
  4.     if (bd->ops && bd->ops->update_status)  
  5.         bd->ops->update_status(bd);  
  6.     mutex_unlock(&bd->update_lock);  
  7. }  
static inline void backlight_update_status(struct backlight_device *bd)
{
	mutex_lock(&bd->update_lock);
	if (bd->ops && bd->ops->update_status)
		bd->ops->update_status(bd);
	mutex_unlock(&bd->update_lock);
}

看下这个内联函数,看到ops就知道了吧,这边调用了bd->ops->update_status这里就调用到了我们自己写的update_status回调函数:

  1. static const struct backlight_ops android_backlight_ops = {  
  2.     .update_status  = android_backlight_update_status,  
  3.     .get_brightness = android_backlight_get_brightness,  
  4. //        .check_fb...     
  5. };  
static const struct backlight_ops android_backlight_ops = {
	.update_status  = android_backlight_update_status,
	.get_brightness = android_backlight_get_brightness,
//        .check_fb...	
};

  1. static int android_backlight_update_status(struct backlight_device *bl)  
  2. {  
  3.     struct android_pwm_data *pd = dev_get_drvdata(&bl->dev);  
  4.     int brightness = bl->props.brightness;  
  5.     int max=bl->props.max_brightness;  
  6.   
  7. /*  if (bl->props.power != FB_BLANK_UNBLANK) 
  8.         brightness = 0; 
  9.  
  10.     if (bl->props.fb_blank != FB_BLANK_UNBLANK) 
  11.         brightness = 0; 
  12. */  
  13.     printk(KERN_INFO "update brightness...\n");  
  14.     if (pd->notify)  
  15.         brightness = pd->notify(pd->dev, brightness);  
  16.     //+++add   
  17.     global_brightness = brightness;  
  18. //  complete(&priv_event);   
  19.     printk(KERN_INFO "complete event....\n");  
  20.     return 0;  
  21. }  
static int android_backlight_update_status(struct backlight_device *bl)
{
	struct android_pwm_data *pd = dev_get_drvdata(&bl->dev);
	int brightness = bl->props.brightness;
	int max=bl->props.max_brightness;

/*	if (bl->props.power != FB_BLANK_UNBLANK)
		brightness = 0;

	if (bl->props.fb_blank != FB_BLANK_UNBLANK)
		brightness = 0;
*/
	printk(KERN_INFO "update brightness...\n");
	if (pd->notify)
		brightness = pd->notify(pd->dev, brightness);
	//+++add
	global_brightness = brightness;
//	complete(&priv_event);
	printk(KERN_INFO "complete event....\n");
	return 0;
}

这里咱也没做什么,因为android模拟器没有真正的背光的设备,我们打印了信息,还有就是一个notify回调函数,这里我们也没有实现,这里我猜想就是这边背光如果涉及到别的deivce的行为的话,这个notify函数可以通知到别的设备。

ok,这边就介绍结束了,我们来启动我们的android模拟器来看下sysfs中backlight下我们自己的节点。



大家可以看到我们自己的device的文件系统,我们cat 出来的brightness就是我们在board-goldfish.c中设置的初始值。

=====================================================

OK,这部分就介绍到这,下面一篇会介绍到我们HAL层中是如何封装我们driver中的接口的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值