总结流程:基于驱动框架写led驱动…
来源:互联网 发布:曲婉婷lll知乎 编辑:程序博客网 时间:2024/06/08 00:56
原文转:http://blog.sina.com.cn/s/blog_14f1867f70102wif2.html
(1)参考s3c24xx-led.c
(2)关键点就是led_classdev_register ,用这个led驱动框架中的注册接口去注册我们的led驱动,
我们通过看sys/class/leds/目录下的有没有我们注册的这个设备驱动的名字。
(3)我们调用led_classdev_register这个led驱动框架中的注册led驱动的函数,是通过填充好的structled_classdev这个类型的结构体,去注册的。
这个structled_classdev结构体中,有一些这个驱动的名字,和操作这个驱动的读或写函数指针,写led硬件对应的是void(*brightness_set)(structled_classdev *led_cdev,
这个structled_classdev结构体还有一个成员brightness;这个成员是将来在我们读这个led硬件的时候,读取出来的值.
这个structled_classdev结构体还有一个成员name,就是硬件的名字,将来会在sys/class/leds/目录下出现,比如是whyx210-led
用户是怎么去读或写led硬件的呢,这部分是在led-class.c中,led驱动框架帮我们完成好了,在内核驱动框架建立起来之后,也就是执行了led-class.c中的
static int __init leds_init(void)函数后,这个函数中的leds_class =class_create(THIS_MODULE, "leds");这个语句,会帮我们创建一个设备类,在sys/cla
ss/目录下,创建的设备类名字是leds,并且在这个函数中又通过leds_class->dev_attrs =led_class_attrs;这个语句,将led_class_attrs,这个所有led设备
通有的属性和方法加上了。这个led_class_attrs是一个结构体,
static struct device_attribute led_class_attrs[] = {
__ATTR(brightness, 0644, led_brightness_show,led_brightness_store),
__ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
#ifdef CONFIG_LEDS_TRIGGERS
__ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
#endif
__ATTR_NULL,
};
这个结构体中的brightness max_brightnesstrigger等,将来就会在sys/class/leds/whyx210-led/目录下出现,这些就是这个硬件拥有的属性文件。
在这个结构体structdevice_attribute中可以看出brightness这个属性文件,有led_brightness_show和led_brightness_store,分别对应的就是读这个led硬件
和写这个led硬件。而max_brightness这个属性文件,有led_max_brightness_show,所以max_brightness这个文件只可以读,可以读取到led硬件当前的值。
led_brightness_show led_brightness_storeled_max_brightness_show这三个就是这个硬件的操作方法。可以通过写或读这两个brightnessmax_brightness
文件,来使用,方法决定了我们可以这么去操作这个硬件。
这三个方法对应的就是三个函数,比如led_brightness_store这个写方法,这个函数里面有一个函数led_set_brightness,这个函数中有一条语句led_cdev->brightness_set(led_cdev,value);,并且led_cdev这个结构体也是
structled_classdev类型的,所以最后我们用户去通过brightness这个属性文件去写led硬件的时候,会去执行led_brightness_storew这个方法,这个方法中,又
通过调用led_set_brightness这个函数,这个函数中通过led_cdev->brightness_set(led_cdev,value);这条语句,最终对应到了structled_classdev结构体中的brightness_set这个函数指针变量,而这个函数指针变量在我们填充那个结构体
structled_classdev中的brightness_set函数指针时,就已经绑定好了我们写的那个写操作硬件的函数了。所以这一条线就打通了.
代码如下:#include
#include
#include
#include //ioremap和iounmap的头文件writel等
#include
#include
#defineGPJ0CONS5PV210_GPJ0CON//这个宏是在gpio-bank.h中定义的,是虚拟地址,这个宏还用到了regs-gpio.h中的宏,
//以此类推。
#define GPJ0DATS5PV210_GPJ0DAT
static struct led_classdev myled;
//这个函数绑定到了structled_classdev这个结构体类型的myled变量中的brightness_set成员,当我们用户写这个led硬件的时候,因为是用led驱动框架
//写的led驱动,所以我们是通过led驱动框架中的brightness这个文件,去写或这个读led硬件的,应为这个文件在驱动框架中具有了可读可写的属性,是在
//struct//device_attribute结构中拥有的,并且最终绑定了到了这个设备类中。所以最后我们用户去通过brightness这个属性文件去写led硬件的时候,会去执行led_br//ightness_store这个方法,这个方法中,又
//通过调用led_set_brightness这个函数,这个函数中通过led_cdev->brightness_set(led_cdev,value);这条语句,最终对应到了struct//led_classdev结构体中的brightness_set这个函数指针变量,而这个函数指针变量在我们填充那个结构体
//structled_classdev中的brightness_set函数指针时,就已经绑定好了我们写的那个写操作硬件的函数了。所以这一条线就打通了.value就是用户要写的值
//value是枚举,是enum led_brightness类型的枚举,这个枚举有三个值,分别是LED_OFF = 0
static void whyx210_led_set(struct led_classdev *led_cdev, enumled_brightness value)
{
printk(KERN_INFO "whyx210_led_set\n");
if (value == LED_OFF) {//用户输入0时全灭对应用户输入的是echo 0 > brightness
writel(0x11111111, GPJ0CON);
writel(((1 << 3) | (1 << 4) | (1 << 5)),GPJ0DAT);
}else if (value == LED_FULL){//用户输入255时全亮对应用户输入的是echo 255 >brightness
writel(0x11111111, GPJ0CON);
writel(((0 << 3) | (0 << 4) | (0 << 5)),GPJ0DAT);
}
}
static int __init whyx210_led_init(void)
{
int ret = -1;
//填充我们要注册的struct led_classdev类型的结构体
myled.name ="whyx210-led";//将来sys/class/leds/目录下的那个led文件的名字。leds这个目录在led-class.c中内核帮我们实现好了
myled.brightness_set = whyx210_led_set;
//去调用led驱动框架中为我们提供的led注册函数led_classdev_register去注册驱动
//在led-class.c中int led_classdev_register(struct device *parent,struct led_classdev *led_cdev)
ret = led_classdev_register(NULL, &myled);
if (ret < 0) {
printk(KERN_ERR "led_classdev_register errro\n");
return ret;
}
printk(KERN_INFO "led_classdev_register success %s\n",myled.name);
return 0;
}
static void __init whyx210_led_exit(void)
{
led_classdev_unregister(&myled);
printk(KERN_INFO "led_classdev_unregister success.\n");
}
module_init(whyx210_led_init);
module_exit(whyx210_led_exit);
MODULE_AUTHOR("why <417842990@qq.com>");
MODULE_DESCRIPTION("whyx210 LED driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("whyx210_led");
- 总结流程:基于驱动框架写led驱动…
- 驱动框架5——基于驱动框架写led驱动
- 基于led框架的驱动分析
- DMA驱动框架流程总结:
- LED驱动框架解析
- 基于platform驱动模型的LED驱动
- 基于mini2440的led驱动编写的总结
- 基于tx2440的led驱动
- 基于tiny6410 的led驱动
- 基于ARM_contexA9 led驱动编程
- 基于ARM_contexA9 led驱动编程
- mtk led驱动总结1
- linux设备驱动归纳总结(五):4.写个简单的LED驱动
- linux设备驱动归纳总结(五):4.写个简单的LED驱动
- linux设备驱动归纳总结(五):4.写个简单的LED驱动
- linux设备驱动归纳总结(五):4.写个简单的LED驱动
- linux设备驱动归纳总结(五):4.写个简单的LED驱动
- linux设备驱动归纳总结(五):4.写个简单的LED驱动
- codevs2830 蓬莱山辉夜
- LED子系统剖析[转]
- 摄像头成像原理
- 数字图像处理常用方法
- svn 如何解决冲突
- 总结流程:基于驱动框架写led驱动…
- 洛谷2105 k皇后
- U-boot启动第一阶段源码分析
- js获取上传文件内容(未完待续)
- 随记一场狼人杀游戏
- codevs1052 地鼠游戏
- QFileDialog 的各种属性设置介绍 .
- 图像分割的重要步骤之——边缘检测
- mac磁盘满解决方案