热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux下的Backlight子系统(二)【转】

转自:http:blog.csdn.netweiqing1981127articledetails8515847版权所有,转载必须说明转自 http:my.csdn.netweiq

转自:http://blog.csdn.net/weiqing1981127/article/details/8515847

版权所有,转载必须说明转自 http://my.csdn.net/weiqing1981127 

原创作者:南京邮电大学  通信与信息系统专业 研二 魏清

三.Backlight核心驱动

下面我们讲讲backlight子系统。背光子系统目录在/driver/video/backlight下,其中背光子系统核心代码是backlight.c

先查看/driver/video/backlight/Makefile

obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o

继续查看/driver/video/backlight/Kconfig

config BACKLIGHT_CLASS_DEVICE

        tristate "Lowlevel Backlight controls"

       depends on BACKLIGHT_LCD_SUPPORT

       default m

所以配置内核make menuconfig时,需要选中这一项。

下面看backlight背光的核心代码backlight.c

static int __init backlight_class_init(void)

{

       backlight_class = class_create(THIS_MODULE, "backlight"); //注册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;

}

我们知道backlight背光子系统的主要就是靠这个类属性,当我们设置背光值就是向类属性中某个成员写背光值,这个类属性就是给用户的一种接口,我们重点看看

#define __ATTR(_name,_mode,_show,_store) { \

       .attr = {.name = __stringify(_name), .mode = _mode },     \

       .show     = _show,                             \

       .store      = _store,                             \

}

static struct device_attribute bl_device_attributes[] = {

       __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),

       __ATTR(brightness, 0644, backlight_show_brightness,

                   backlight_store_brightness),

       __ATTR(actual_brightness, 0444, backlight_show_actual_brightness,

                   NULL),

       __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),

       __ATTR_NULL,

};

很明显,在backlight类中我们创建了bl_power,brightness,actural_brightness,max_brightness四个成员,其中brightness是当前亮度,max_brightness是最大亮度。当用户层通过cat或者echo命令就会触发这些成员。对于这些属性的读写函数,我们先看看读的函数backlight_show_max_brightness吧

static ssize_t backlight_show_max_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.max_brightness);  //输出最大亮度

}

这个函数很简单,但是重点是引入了几个backlight背光子系统的几个重要的数据结构,我们好好学习下。

首先是backlight背光子系统的设备结构体backlight_device

struct backlight_device {

       struct backlight_properties props;  //背光属性

       struct mutex update_lock;

       struct mutex ops_lock;

       struct backlight_ops *ops;    //背光操作函数,类似于file_operations

       struct notifier_block fb_notif;

       struct device dev;  //内嵌设备

};

下面先看看背光属性结构体backlight_properties

struct backlight_properties {

       int brightness;  //当前背光值

       int max_brightness;  //最大背光值

       int power;

       int fb_blank;

       unsigned int state;

};

再看看背光操作函数结构体

struct backlight_ops {

       unsigned int options;

#define BL_CORE_SUSPENDRESUME       (1 <<0)

       int (*update_status)(struct backlight_device *);   //改变背光状态

       int (*get_brightness)(struct backlight_device *);  //获取背光值

       int (*check_fb)(struct fb_info *);

};

好了,我们继续看backlight类属性中写的函数,例如设置当前背光值函数backlight_store_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);  //调用backlight_update_status设备背光值

                     rc = count;

              }

       }

       mutex_unlock(&bd->ops_lock);

       backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);

       return rc;

}

跟踪backlight_update_status

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); //调用背光操作函数中改变背光状态函数update_status

       mutex_unlock(&bd->update_lock);

}

对于这个backlight背光核心层驱动backlight.c,剩下的就是这个pwm.c给我们提供了哪些接口函数了。

struct backlight_device *backlight_device_register(const char *name,

              struct device *parent, void *devdata, struct backlight_ops *ops)

void backlight_device_unregister(struct backlight_device *bd)

EXPORT_SYMBOL(backlight_device_register);  //注册背光设备

EXPORT_SYMBOL(backlight_device_unregister); //注销背光设备

这些接口很简单,就不细说了,这样我们的backlight子系统的核心层就介绍完了。

四.基于PWM&Backlight的蜂鸣器驱动

下面我们结合上面的PWM核心层和Backlight背光子系统核心层,根据基于pwm的背光驱动/driver/video/backlight/pwm_bl.c来修改成基于Mini2440的蜂鸣器驱动。

先查看/driver/video/backlight/Makefile

obj-$(CONFIG_BACKLIGHT_PWM)   += pwm_bl.o

继续查看/driver/video/backlight/Kconfig

config BACKLIGHT_PWM

       tristate "Generic PWM based Backlight Driver"

       depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM

       help

         If you have a LCD backlight adjustable by PWM, say Y to enable

         this driver.

我们的HAVE_PWM和BACKLIGHT_CLASS_DEVICE分别是在前面讲pwm核心和backlight核心时已经编译了,所以配置内核make menuconfig 时,需要再选中"Generic PWM based Backlight Driver"这项。

好了,我们先把我们的蜂鸣器移植进去吧,首先我们知道蜂鸣器使用的是GPB0端口,该端口如果工作在TOU0模式,就可以通过设备定时器的TCNT和TCMP来控制定时器的波形而来。先打开mini2440的BSP文件mach-mini2440.c,如下添加

static struct platform_device s3c_backlight_device = {

       .name             = "pwm-backlight",           //设备名

       .dev        = {

              .parent    = &s3c_device_timer[0].dev,  //该设备基于pwm中的0号定时器

              .platform_data = &s3c_backlight_data,

       },

       .id=0,     //对应的就是pwm0

};

添加平台数据

static struct platform_pwm_backlight_data s3c_backlight_data = {

       .pwm_id         = 0,   //对应的就是Timer0

       .max_brightness     = 1000,  //最大亮度

       .dft_brightness       = 10 ,      //当前亮度

       .pwm_period_ns    = 800000,  //这就是前面说的T0,即输出时钟周期

       .init         = s3c_bl_init,  //端口初始化

};

注意到平台数据中定义了init函数,由于在蜂鸣器的初始化时,需要对GPB0设置为TOUT0模式,所以代码如下编写

static int s3c_bl_init(struct device *dev)

{

       s3c2410_gpio_pullup(S3C2410_GPB(0),0);   // GPB0不上拉

       s3c2410_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPB0_TOUT0); // GPB0设置为TOUT0

       return 0;

}

然后把这个s3c_backlight_device加入到mini2440_devices数组

static struct platform_device *mini2440_devices[] __initdata = {

       ……

       &s3c_device_timer[0],

       &s3c_backlight_device, //添加

};

最后添加头文件

#include

这样配置完后,进行make zImage生成zImage内核镜像。

好了,下面我们分析下基于pwm的背光驱动/driver/video/backlight/pwm_bl.c

static struct platform_driver pwm_backlight_driver = {

       .driver            = {

              .name      = "pwm-backlight", //驱动名

              .owner    = THIS_MODULE,

       },

       .probe            = pwm_backlight_probe, //探测函数

       .remove          = pwm_backlight_remove,

       .suspend  = pwm_backlight_suspend,

       .resume          = pwm_backlight_resume,

};

static int __init pwm_backlight_init(void)

{

       return platform_driver_register(&pwm_backlight_driver);

}

注意上面的pwm_backlight_driver中的驱动名"pwm-backlight"和我们刚才移植时添加的设备名"pwm-backlight"是一致的,这样设备和驱动就能匹配成功。下面看探测函数

static int pwm_backlight_probe(struct platform_device *pdev)

{

       struct platform_pwm_backlight_data *data = pdev->dev.platform_data;

       struct backlight_device *bl;

       struct pwm_bl_data *pb;  //本驱动的私有结构体

       int ret;

       if (!data) {

              dev_err(&pdev->dev, "failed to find platform data\n");

              return -EINVAL;

       }

       if (data->init) {  //初始化端口,这个端口函数在BSP中定义

              ret = data->init(&pdev->dev);

              if (ret <0)

                     return ret;

       }

       pb = kzalloc(sizeof(*pb), GFP_KERNEL); //分配pwm_bl_data空间

       if (!pb) {

              dev_err(&pdev->dev, "no memory for state\n");

              ret = -ENOMEM;

              goto err_alloc;

       }

       pb->period = data->pwm_period_ns;   //获取周期

       pb->notify = data->notify;

       pb->pwm = pwm_request(data->pwm_id, "backlight"); //注册pwm设备

       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");

       bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,

                     pb, &pwm_backlight_ops); //注册backlight设备

       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;

       backlight_update_status(bl);  //先点亮背光

       platform_set_drvdata(pdev, bl); //设置bl为私有数据

       return 0;

err_bl:

       pwm_free(pb->pwm);

err_pwm:

       kfree(pb);

err_alloc:

       if (data->exit)

              data->exit(&pdev->dev);

       return ret;

}

对于这个驱动,我们重点关注的是注册backlight设备时传入的参数pwm_backlight_ops,因为我们之前分析backlight背光子系统时说过,背光设备结构体中有个操作背光的函数集合,在我们的pwm_bl.c中,就需要定义这个操作背光的函数集合,也就是pwm_backlight_ops

static struct backlight_ops pwm_backlight_ops = {

       .update_status = pwm_backlight_update_status, //更新背光亮度

       .get_brightness       = pwm_backlight_get_brightness, //获取背光亮度

};

获取背光亮度函数pwm_backlight_get_brightness很简单,跟踪得到

static int pwm_backlight_get_brightness(struct backlight_device *bl)

{

       return bl->props.brightness;

}

我们重点看更新背光亮度函数pwm_backlight_update_status

static int pwm_backlight_update_status(struct backlight_device *bl)

{

       struct pwm_bl_data *pb = 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;

       if (pb->notify)

              brightness = pb->notify(brightness);

       if (brightness == 0) {  //背光值为0,关闭背光

              pwm_config(pb->pwm, 0, pb->period);

              pwm_disable(pb->pwm);

       } else {   //调用pwm中的API设置背光

              pwm_config(pb->pwm, brightness * pb->period / max, pb->period);

              pwm_enable(pb->pwm);

       }

       return 0;

}

好了,这样我们的pwm_bl.c也分析完了。在使用backlight子系统的时候,我们只需要在probe函数中注册pwm和backlight设备,然后定义背光操作函数集合即可。

五.驱动测试

实验环境:内核linux2.6.32.2,arm-linux-gcc交叉编译器,mini2440开发板

下面我们进行对上面的驱动进行测试,按照上面的步骤操作,将上文已经编译好的zImage烧入开发板,通过超级终端控制,能控制蜂鸣器的发出的声音频率。

 技术分享

Linux下的Backlight子系统(二)【转】


推荐阅读
  • Python学习:环境配置与安装指南
    Python作为一种跨平台的编程语言,适用于Windows、Linux和macOS等多种操作系统。为了确保本地已成功安装Python,用户可以通过终端或命令行界面输入`python`或`python3`命令进行验证。此外,建议使用虚拟环境管理工具如`venv`或`conda`,以便更好地隔离不同项目依赖,提高开发效率。 ... [详细]
  • 本文深入解析了 Apache 配置文件 `httpd.conf` 和 `.htaccess` 的优化方法,探讨了如何通过合理配置提升服务器性能和安全性。文章详细介绍了这两个文件的关键参数及其作用,并提供了实际应用中的最佳实践,帮助读者更好地理解和运用 Apache 配置。 ... [详细]
  • 在Linux环境下,本文详细探讨了Apache服务器中CGI技术的应用与实现。首先,通过使用yum包管理器安装了必要的软件,如PHP。安装完成后,对Apache服务器进行了配置,确保CGI功能正常运行。此外,还介绍了如何编写和调试CGI脚本,以及如何在实际环境中部署这些脚本以提供动态网页内容。实验结果表明,通过合理的配置和优化,Apache服务器能够高效地支持CGI应用程序,为用户提供丰富的交互体验。 ... [详细]
  • PHP中元素的计量单位是什么? ... [详细]
  • 本文深入探讨了 iOS 开发中 `int`、`NSInteger`、`NSUInteger` 和 `NSNumber` 的应用与区别。首先,我们将详细介绍 `NSNumber` 类型,该类用于封装基本数据类型,如整数、浮点数等,使其能够在 Objective-C 的集合类中使用。通过分析这些类型的特性和应用场景,帮助开发者更好地理解和选择合适的数据类型,提高代码的健壮性和可维护性。苹果官方文档提供了更多详细信息,可供进一步参考。 ... [详细]
  • 解决基于XML配置的MyBatis在Spring整合中出现“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”问题的方法
    在将Spring与MyBatis进行整合时,作者遇到了“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”的问题。该问题主要出现在使用XML文件配置DAO层的情况下,而注解方式配置则未出现类似问题。作者详细分析了两个配置文件之间的差异,并最终找到了解决方案。本文将详细介绍问题的原因及解决方法,帮助读者避免类似问题的发生。 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
  • 本文详细探讨了Java集合框架的使用方法及其性能特点。首先,通过关系图展示了集合接口之间的层次结构,如`Collection`接口作为对象集合的基础,其下分为`List`、`Set`和`Queue`等子接口。其中,`List`接口支持按插入顺序保存元素且允许重复,而`Set`接口则确保元素唯一性。此外,文章还深入分析了不同集合类在实际应用中的性能表现,为开发者选择合适的集合类型提供了参考依据。 ... [详细]
  • 本文详细介绍了使用响应文件在静默模式下安装和配置Oracle 11g的方法。硬件要求包括:内存至少1GB,具体可通过命令`grep -i memtotal /proc/meminfo`进行检查。此外,还提供了详细的步骤和注意事项,确保安装过程顺利进行。 ... [详细]
  • 新年伊始,正是学习的最佳时机。本文全面解析了CK1957-Zookeeper的核心概念与实践技巧,旨在帮助初学者快速掌握这一深度学习工具。通过详细的理论讲解和实际操作示例,读者可以更好地理解Zookeeper的工作原理及其在分布式系统中的应用。无论是新手还是有一定基础的学习者,都能从中受益匪浅。 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • 本文详细介绍了如何在Linux系统中搭建51单片机的开发与编程环境,重点讲解了使用Makefile进行项目管理的方法。首先,文章指导读者安装SDCC(Small Device C Compiler),这是一个专为小型设备设计的C语言编译器,适合用于51单片机的开发。随后,通过具体的实例演示了如何配置Makefile文件,以实现代码的自动化编译与链接过程,从而提高开发效率。此外,还提供了常见问题的解决方案及优化建议,帮助开发者快速上手并解决实际开发中可能遇到的技术难题。 ... [详细]
  • 本文介绍了在PHP环境中优化表格列表和表单Label样式的技巧,通过CSS代码提升表单的视觉效果。具体包括为每个标签添加箭头背景,并在标签获得焦点时实现背景高亮的效果。示例代码展示了如何为“姓名”和“邮件”字段应用这些样式,适用于phpStudy开发环境。 ... [详细]
  • Java中高级工程师面试必备:JVM核心知识点全面解析
    对于软件开发人员而言,随着技术框架的不断演进和成熟,许多高级功能已经被高度封装,使得初级开发者只需掌握基本用法即可迅速完成项目。然而,对于中高级工程师而言,深入了解Java虚拟机(JVM)的核心知识点是必不可少的。这不仅有助于优化性能和解决复杂问题,还能在面试中脱颖而出。本文将全面解析JVM的关键概念和技术细节,帮助读者全面提升技术水平。 ... [详细]
  • Jenkins学习精华:自动化构建与持续集成入门指南
    本文综合了网络资源及同事分享的PPT内容,详细介绍了Jenkins在自动化构建与持续集成中的应用。首先涵盖了Jenkins的安装与配置流程,接着阐述了如何根据项目需求设定自动化编译任务,包括确定开发环境、选择合适的编译工具以及实现代码的自动更新等关键步骤。特别强调了在SVN环境中通过命令行实现代码自动拉取的最佳实践。 ... [详细]
author-avatar
手机用户2602879975
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有