转自: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 <linux/pwm_backlight.h>

这样配置完后,进行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子系统(二)【转】的更多相关文章

  1. Linux下的Backlight子系统(一)【转】

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

  2. linux下动态链接库解决方案(二)

    以前写过一个关于linux下用c++写动态链接库无法通过的解决方案,今天看到<linux C程序设计-王者归来>这本书,书中有个更容易的解决方案,特此记录下来 书中使用的是c语言,我改用c ...

  3. Linux块设备IO子系统(二) _页高速缓存

    磁盘驱动就是实现磁盘空间和内存空间数据上的交互,在上一篇中我们讨论了内存端的Page Segment Block Sector相关的概念,本文以3.14内核为例,讨论这部分内存是如何被组织管理的.我们 ...

  4. Linux下的RTC子系统

    转自:http://blog.csdn.net/weiqing1981127/article/details/8484268 实时时钟的作用主要是为操作系统提供一个可靠的时间,并在断电下,RTC时钟也 ...

  5. Linux下环境搭建(二)——jenkins+gitlab配置

    配置jenkins+gitlab环境,需要依托java环境,在之前的博文中,已配置好java环境,所以可以直接搭建这两个工具的环境即可. jenkins配置 jenkins的配置方法,在之前windo ...

  6. Linux下GPIO驱动(二) ----s3c_gpio_cfgpin();gpio_set_value();

    首先来看s3c_gpio_cfgpin(); int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) { struct s3c_gpio_ ...

  7. linux 下shell程序(二)

    输入和输出 输入指的是Shell程序读入数据.有从文件读取.从用户输入读取等方式读入数据.输出指的是Shell程序的运行 结果的处理,可以显示到屏幕或保存到文件. 用ceho命令输出结果 echo $ ...

  8. linux下安装vsftp(二)

    安装vsftpd 1.以管理员(root)身份执行以下命令 yum install vsftpd 2.设置开机启动vsftpd ftp服务 chkconfig vsftpd on 3.启动vsftpd ...

  9. backlight 子系统(转载)

    http://blog.csdn.net/weiqing1981127/article/details/8511676   Linux下的Backlight子系统(一) http://blog.csd ...

随机推荐

  1. 10-Mysql数据库----数据的增删改

    本节重点: 插入数据 INSERT 更新数据 UPDATE 删除数据 DELETE 再来回顾一下之前我们练过的一些操作,相信大家都对插入数据.更新数据.删除数据有了全面的认识.那么在mysql中其实最 ...

  2. throw er; // Unhandled 'error' event&Error: ENOENT: no such file or directory,

    今天做一个文件上传的项目时, 用express-formidable往硬盘里面存文件时, 报  ENOENT:no such file or directory 原因就是程序不能像别的语言一样不存在就 ...

  3. lintcode-92-背包问题

    92-背包问题 在n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为A[i] 注意事项 你不可以将物品进行切割. 样例 如果有4个物品[2, 3, 5, 7] 如果背包 ...

  4. OpenCV膨胀和腐蚀示例代码

    #include<cv.h> #include<highgui.h> int main(int argc, char** argv) { IplImage* img = cvL ...

  5. Java中Model1和Model2

    Model1和Model2是java web的两种架构模式.这两种模式各有优缺点,都有各自适合使用的场景. Model1 首先,从分层的角度说,Model1模式可以看作是由两层组成:视图层和模型层. ...

  6. kafka卡顿

    一次kafka卡顿事故排查过程 https://www.cnblogs.com/yougewe/p/8975550.html 由于一次功能上线后,导致某数据量急剧下滑,给我们紧张的呢!排查过程也是个学 ...

  7. Walk 解题报告

    Walk 题目描述 给定一棵 \(n\) 个节点的树,每条边的长度为 \(1\),同时有一个权值\(w\).定义一条路径的权值为路径上所有边的权值的最大公约数.现在对于任意 \(i \in [1,n] ...

  8. Ubuntu下安装LNMP之nginx的安装

    Nginx 最初是作为一个 Web 服务器创建的,用于解决 C10k 的问题.作为一个 Web 服务器,它可以以惊人的速度为您的数据服务.但 Nginx 不仅仅是一个 Web 服务器,你还可以将其用作 ...

  9. 解决导出为Excel时文件名乱码的问题。

    以前代码:public static void htmlToExcel(HttpContext context, string title, string html, string fileCss = ...

  10. 在Ubuntu下编译WebKit源码--qt

    转载自:http://www.cnblogs.com/panderen/archive/2011/10/18/2216154.html 在朋友的介绍下有幸認识了WebKit这个让人心动的开源浏览器内核 ...