Chinaunix首页 | 论坛 | 博客
  • 博客访问: 260524
  • 博文数量: 128
  • 博客积分: 65
  • 博客等级: 民兵
  • 技术积分: 487
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-24 17:43
个人简介

人生境界:明智、中庸、诚信、谦逊

文章分类

全部博文(128)

文章存档

2014年(12)

2013年(116)

我的朋友

分类: 嵌入式

2013-09-27 13:11:57

原文地址:Linux驱动框架----hwmon 作者:apple_guet

写在前面的话:

对于框架,我觉得就是在一定规范的形式下去实现你要的功能。这里就涉及到一个变与不变的地方。你所要实现的功能会是千差万别的---这就是变的地方,而所谓既定的规范,包括建立目录和属性文件这是Linux系统已经为我们做好了的,我们只需要直接拿来引用就OK了。

那么今天,我们就来看看hwmon框架是怎么样的。


对hwmon而言,它是sysfs框架下的一个类,但是所有有关该类与sys的接口都已经在drivers/hwmon/hwmon.c实现,因而我们也不必过多的关心。

那么我们到底要做些什么呢?

对于你要实现的功能部分,你就自己去想象吧,下面我们来说说在我们的程序中对于不变的那部分要如何去实现。

我就以最基本的读CPU温度的程序为例,来说明整个框架的编写。

一.作为驱动,首先我们要做就是驱动的注册和撤销。

因此,在XXX_hwmon_init()函数中对hwmon驱动和该驱动的属性文件等进行注册。

my_hwmon_dev = hwmon_device_register(NULL);

ret = sysfs_create_group(&my_hwmon_dev->kobj,&my_hwmon_attribute_group);

ret = create_sysfs_temp_files(&my_hwmon_dev->kobj);

在有这么多的注册函数时,对于函数的异常处理,我个人觉得用goto来实现,比较直观和易用,让人看起来一目了然。

复制代码
 1 static int __init my_hwmon_init(void)  2 {  3 int ret;  4  5 printk(KERN_INFO "my cpu temperature hwmon enter!\n");  6  7 my_hwmon_dev = hwmon_device_register(NULL);  8 if (IS_ERR(my_hwmon_dev)) {  9 ret = -ENOMEM; 10 printk(KERN_ERR "my_hwmon_device_register fail!\n"); 11 goto fail_hwmon_device_register; 12  } 13 14 ret = sysfs_create_group(&my_hwmon_dev->kobj, 15 &my_hwmon_attribute_group); 16 if (ret) { 17 printk(KERN_ERR "fail to create my hwmon!\n"); 18 goto fail_create_group_hwmon; 19  } 20 21 ret = create_sysfs_temp_files(&my_hwmon_dev->kobj); 22 if (ret) { 23 printk(KERN_ERR "fail to create temperature files!\n"); 24 goto fail_create_sysfs_temp_files; 25  } 26 return ret; 27 28 fail_create_sysfs_temp_files: 29 sysfs_remove_group(&my_hwmon_dev->kobj, &my_hwmon_attribute_group); 30 fail_create_group_hwmon: 31  hwmon_device_unregister(my_hwmon_dev); 32 fail_hwmon_device_register: 33 return ret; 34 }
复制代码

而在XXX_hwmon_exit()函数中,和XXX_hwmon_init()函数相对应的,以相反的顺序对已注册的设备进行撤销。

remove_sysfs_temp_files(&my_hwmon_dev->kobj);

sysfs_remove_group(&my_hwmon_dev->kobj,&my_hwmon_attribute_group);

hwmon_device_unregister(my_hwmon_dev);

好了,至此,hwmon架构的初始化和撤销的工作已经完成。

二.接下去就是对hwmon下的各种属性文件的创建和对温度的读写。

1.hwmon整体属性框架

总的来讲分为三部曲:

首先,每个hwmon设备都会有自己独有的属性,这些独有属性就被SENSOR_DEVICE_ATTR声明为struct attribute结构体。

SENSOR_DEVICE_ATTR具体定义在include/linux/hwmon-sysfs.h中:

1 #define SENSOR_DEVICE_ATTR(_name, _mode, _show, _store, _index) \ 2 3 struct sensor_device_attribute sensor_dev_attr_##_name          \ 4 5 = SENSOR_ATTR(_name, _mode, _show, _store, _index)

在程序中,则被写作:

1 static SENSOR_DEVICE_ATTR(name, S_IRUGO, get_my_hwmon_name, NULL, 0);

 然后,加入到sysfs框架的struct attribute属性结构体数组中,注意该结构体数组最后一项必须以NULL结尾。

struct attribute定义在include/linux/sysfs.h中。

1 static struct attribute *my_hwmon_attributes[] = { 2 &sensor_dev_attr_name.dev_attr.attr, 3  NULL, 4 };

最后,将这些众多的属性汇总到结构struct attribute_group中。这个struct attribute_group被sysfs_create_group()函数调用建立整个属性框架。

struct attribute_group定义在include/linux/sysfs.h中。

1 static struct attribute_group my_hwmon_attribute_group = { 2 .attrs = my_hwmon_attributes, 3 };

在我的程序中,这里只有一个属性—name,表示该hwmon驱动的名称。

2.温度相关属性文件的建立

在上面,整个hwmon的框架已经建立,接下来就是温度的读取,显示。这个过程其实是sysfs框架的内容。

首先,确定会有多少属性,每个属性文件都会被SENSOR_DEVICE_ATTR声明为struct attribute结构体。其中的_show和_store是以函数形式实现,因此对应的实现相应的函数,若没有这个功能的实现就以NULL代替;

_show表示的是从属性文件中读取出数据。

_store表示的是向属性文件中写入数据。

因此,如果该属性文件是不可写是,_store实现为NULL。

然后,将同一seneor的属性加入到sysfs框架的struct attribute属性结构体数组中,注意该结构体数组最后一项必须以NULL结尾,被sysfs_create_files()函数调用。

以上两步是建立属性文件最基本的两步,我们的具体功能可以在_show和_store两个函数中去实现。当然对于一些复杂的设备来讲仅仅这两步是不够的,如果该设备属于平台驱动或者是某一大类设备,如I2C,我们此时就需要根据具体情况去声明相应的结构,并按照相应结构的规范去操作。

在我的程序中仅限于前两步,因为程序中并未涉及到任何其他设备,只是简单的读取了温度寄存器。程序中定义了两个属性my_cpu_temp_label和get_my_cpu_temp。

下面是我模块在加载后生成目录的tree型图:

       

这些就是我对hwmon框架在目前基础上的了解。

最后向大家做个推荐啊:我的所有程序都会在github上,所以,大家要是有兴趣的话,可以去github上去clone。

我的github地址为:

这篇文章中完整代码的下载方式为:git clone git://github.com/Antonio-Zhou/LoongsonDriver.git

下载之后,其中会有一个cpu_temp的目录,里面存放着makefile文件和源代码。

希望大家多多提意见哦

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