Android模拟器学framework和driver
3716 点击·0 回帖
![]() | ![]() | |
![]() | 前面介绍了battery的相关的东西,现在我们来介绍下backlight模块,背光主要是用来调节显示屏亮度的,一般背光都是用PWM控制的,调节占空比达到改变有效电压值来调节光的强弱。 背光的移植在linux中虽然不是那么难,但是背光这个组件对我们嵌入式设备的续航能力有很大的影响,一般背光上面加的电压会有20多的电压,所以这部分会很耗电的,相当于是开了个大灯泡。 现在我们先来看下Android goldfish中的背光代码,哈哈,没找到吧,没有,我们打开模拟器,看sysfs中,也是没有具体的背光的文件的,所以这里我们得自己实现,自己写代码练习练习,毕竟这部分不是非常的难,参考drivers/video/backlight/下的pwm_bl.c文件,基本可以仿照,我们要做的事情很简单,创建背光相关的文件系统即可,不需要去控制硬件做什么动作,因为我们本来就没有硬件。 首先看下video中的makefile,如果backlight/没有选中就选中它,不然我们的模块不会编译进去。然后再看下backlight/下的Makefile [cpp] 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 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先编译进去,直接这样改,我比较懒 呵呵呵, [cpp] obj-y += backlight.o 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函数: [cpp] 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 = %ldn", 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); 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 = %ldn", 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中创建了一系列的文件系统, [cpp] <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, "%dn", 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 %lun", power); if (bd->props.power != power) { bd->props.power = power; backlight_update_status(bd); } rc = count; } mutex_unlock(;bd->ops_lock); return rc; } <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, "%dn", 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 %lun", 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函数 [cpp] 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); 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注册平台驱动,看下传入的参数: [cpp] static struct platform_driver Android_backlight_driver = { .driver ={ .name = "Android-backlight", .owner = THIS_MODULE, }, .probe = Android_backlight_probe, // .remove = ........ // .suspend // .resume }; 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 [cpp] 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 = ...; }; 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中进行注册: [cpp] 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); <span style="color:#ff0000;">Android_register_device(;Android_backlight_device, ;Android_backlight_data);</span> } 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); <span style="color:#ff0000;">Android_register_device(;Android_backlight_device, ;Android_backlight_data);</span> } 这边Android_backlight_data结构体主要是做一个背光的初始化。 接下来我们看一下probe函数, [cpp] 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 datan"); 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 staten"); 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 backlightn"); ret = PTR_ERR(pb->pwm); goto err_pwm; } else dev_dbg(;pdev->dev, "got pwm for backlightn"); */ 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 backlightn"); 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; } 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 datan"); 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 staten"); 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 backlightn"); ret = PTR_ERR(pb->pwm); goto err_pwm; } else dev_dbg(;pdev->dev, "got pwm for backlightn"); */ 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 backlightn"); 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回调函数,有的话执行,没有的话跳过。 [cpp] if(data->init) { ret=data->init(;pdev->dev); if(ret<0) return ret; } if(data->init) { ret=data->init(;pdev->dev); if(ret<0) return ret; } 这边比较重要的是backlight_device_register函数www.atcpu.com [cpp] 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=%sn", 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); 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=%sn", 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函数的最后一个参数,这里提供了我们可以自己定义的几个回调函数, [cpp] 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 *); }; 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个回调函数挂上去: [cpp] static const struct backlight_ops Android_backlight_ops = { .update_status = Android_backlight_update_status, .get_brightness = Android_backlight_get_brightness, // .check_fb... }; static const struct backlight_ops Android_backlight_ops = { .update_status = Android_backlight_update_status, .get_brightness = Android_backlight_get_brightness, // .check_fb... }; 然后我们去实现这2个函数,就基本完成了我们的驱动了,看函数名字就知道这2个函数的作用,一个是用来更新我们的背光亮度,还有一个是用来得到我们的光强。 [cpp] static int Android_backlight_get_brightness(struct backlight_device *bl) { printk(KERN_INFO "[Android]---get brightness...n"); return bl->props.brightness; } 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函数一起分析: [cpp] 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; } 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中实现: [cpp] 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, "%dn", 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 %lun", brightness); bd->props.brightness = brightness; backlight_update_status(bd); rc = count; } } mutex_unlock(;bd->ops_lock); return rc; } 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, "%dn", 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 %lun", brightness); bd->props.brightness = brightness; backlight_update_status(bd); rc = count; } } mutex_unlock(;bd->ops_lock); return rc; } 当我们向brightness这个文件节点中写入我们要设置的背光亮度的时候会调用store这个回调函数,我们来看下主要做了哪些事情,跟我们在driver层自己写的update函数到底有什么关系呢? 前面都是一大堆不用看的代码,这里最重要的看这个 [cpp] if (bd->ops) { if (brightness > bd->props.max_brightness) rc = -EINVAL; else { pr_debug("backlight: set brightness to %lun", brightness); <span style="color:#ff0000;"> bd->props.brightness = brightness; backlight_update_status(bd);</span> rc = count; } } if (bd->ops) { if (brightness > bd->props.max_brightness) rc = -EINVAL; else { pr_debug("backlight: set brightness to %lun", brightness); <span style="color:#ff0000;"> bd->props.brightness = brightness; backlight_update_status(bd);</span> rc = count; } } 首先是把brightness写进我们的背光属性结构体中,这样就更新了我们数据结构中的背光亮度在值,但是这样做是不够的,因为我们最终要控制的是硬件,所以看下之后我们调用了backlight_update_status函数,ok,看下这个函数的定义: /include/linux/backlight.h [cpp] 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); } 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回调函数: [cpp] static const struct backlight_ops Android_backlight_ops = { .update_status = Android_backlight_update_status, .get_brightness = Android_backlight_get_brightness, // .check_fb... }; static const struct backlight_ops Android_backlight_ops = { .update_status = Android_backlight_update_status, .get_brightness = Android_backlight_get_brightness, // .check_fb... }; [cpp] 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; } 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中的接口的。 摘自 zhangjie201412的专栏 | |
![]() | ![]() |