Linux开发八_LED驱动

来源:互联网 发布:shell是什么软件 编辑:程序博客网 时间:2024/06/05 10:24

Linux开发八

LED驱动

象棋小子    1048272975

Linux内核支持多种驱动框架,其中就支持led这样的设备模型。Linux内核实现了一个虚拟的文件系统sysfs,用于提供一个从用户空间访问内核设备的方法。笔者此处就基于sysfs文件系统的led驱动做一个简单的介绍。

1. led驱动目录

在/drivers/leds目录下实现了Linux内核的led驱动框架。leds目录下Kconfig对led驱动进行配置,如配置led驱动支持、led class支持、特定平台支持等。led驱动可分为平台相关和无关这两部分,平台无关的部分无需任何移植,平台相关的部分需根据特定平台实现led驱动框架的硬件层访问接口。

平台无关部分

# LED Core

obj-$(CONFIG_NEW_LEDS) +=led-core.o

obj-$(CONFIG_LEDS_CLASS)+= led-class.o

obj-$(CONFIG_LEDS_CLASS_FLASH)+= led-class-flash.o

obj-$(CONFIG_LEDS_TRIGGERS)+= led-triggers.o

针对s3c2416特定平台的驱动

obj-$(CONFIG_LEDS_S3C24XX)+= leds-s3c24xx.o

2. led平台驱动相关

Linux内核把平台驱动程序分成两部分,一部分为设备,另一部分为驱动。Linux内核已经支持多个平台驱动,对于未实现的平台,这是需要移植的部分。

2.1. 注册设备

设备信息包含了设备的名字、独有的资源等等一些驱动程序的硬件或自定义信息。通过platform_add_devices(platform_device_register)函数将定义的平台设备注册到内核中,注册成功后,在/sys/devices/platform出现相应的设备目录。

/* LED devices */

static structs3c24xx_led_platdata home_pdata_led4 = {

       .gpio             =S3C2410_GPE(13),

       .flags             =S3C24XX_LEDF_TRISTATE,

       .name            ="led4",

       .def_trigger   ="timer",

};

 

static structs3c24xx_led_platdata home_pdata_led5 = {

       .gpio             =S3C2410_GPE(11),

       .flags             =S3C24XX_LEDF_TRISTATE,

       .name            ="led5",

       .def_trigger   ="nand-disk",

};

 

static struct s3c24xx_led_platdatahome_pdata_led6 = {

       .gpio             =S3C2410_GPL(13),

       .flags             =S3C24XX_LEDF_TRISTATE,

       .name            ="led6",

};

 

static structs3c24xx_led_platdata home_pdata_led7 = {

       .gpio             =S3C2410_GPE(12),

       .flags             =S3C24XX_LEDF_TRISTATE,

       .name            ="led7",

};

 

static structplatform_device home_led4 = {

       .name            ="s3c24xx_led",

       .id          = 0,

       .dev        = {

              .platform_data = &home_pdata_led4,

       },

};

 

static structplatform_device home_led5 = {

       .name            ="s3c24xx_led",

       .id          = 1,

       .dev        = {

              .platform_data = &home_pdata_led5,

       },

};

 

static structplatform_device home_led6 = {

       .name            ="s3c24xx_led",

       .id          = 2,

       .dev        = {

              .platform_data = &home_pdata_led6,

       },

};

 

static structplatform_device home_led7 = {

       .name            ="s3c24xx_led",

       .id          = 3,

       .dev        = {

              .platform_data = &home_pdata_led7,

       },

};

2.2. 注册驱动

对于s3c2416平台来说,led驱动在leds-s3c24xx.c文件中。

static structplatform_driver s3c24xx_led_driver = {

       .probe    =s3c24xx_led_probe,

       .remove = s3c24xx_led_remove,

       .driver = {

              .name     ="s3c24xx_led",

       },

};

 

module_platform_driver(s3c24xx_led_driver);

module_platform_driver()为宏定义,会自动去替换module_init()和module_exit()功能,该驱动中module_init()和module_exit()宏分别调用platform_driver_register()和platform_driver_unregister()。platform_driver_register()为驱动注册函数,当驱动加载的时候,就会执行该函数。s3c24xx_led_driver结构体中定义了驱动的name,驱动注册时,内核会遍历比较驱动name与注册的平台设备name,若一致,就将两者绑定,调用探测函数s3c24xx_led_probe()。探测函数s3c24xx_led_probe()通过调用led_classdev_register()这个函数注册一个新的led设备类对象,实现在目录/sys/class/leds创建子目录led_cdev->name和属性brightness、max_brightness等。

3. 应用编程

在/sys/class/leds目录下有相应的led设备子目录,假设进入led4目录,会看到有brightness、max_brightness等属性文件。通过改变brightness属性文件的值,即可控制led灯的亮灭。

在控制台对brightness文件写入0或1控制led灯的亮灭。

echo 1 >/sys/class/leds/led4/brightness // 亮灯

echo 0 >/sys/class/leds/led4/brightness // 灭灯

也可以通过应用程序访问sysfs中的led设备文件控制led等的亮灭。以led_test.c文件为例如下:

#include"fcntl.h"

#include"unistd.h"

#include"sys/types.h"

#include"stdio.h"

#include"stdlib.h"

 

void led_control(intindex, int on)

{

       int fd;

       char buf[1024];

       char path[] = "/sys/class/leds/led4/brightness";

       if (index == 4) { // led 4

              fd = open(path, O_RDWR);

                  if(fd < 0) { 

                       printf("Open failed\n");    

                     exit(1); 

            }

              sprintf(buf, "%d", on);

              if (write(fd, buf, strlen(buf)) != strlen(buf)) { 

                     close(fd);

                       printf("Write failed\n");    

                     exit(1);  

              }   

              close(fd); 

       }

}

 

int main(void)

{

       while (1) {

              led_control(4, 1);

              sleep(1);

              led_control(4, 0);

              sleep(1);

       }

}

用arm-linux-gcc静态编译,使之生成arm CPU可执行的指令,并且可脱离任何库独立运行,arm-linux-gcc -static -o led_test led_test.c,生成led_test可执行文件。复制可执行文件到根文件系统,目标板启动后在目录输入./led_test即可执行。

4. 附录

https://pan.baidu.com/s/1slczwhJ

bootloader源码以及使用说明

https://pan.baidu.com/s/1eRDJtNs

Qt5.8官网源码

https://pan.baidu.com/s/1nuGmSqt

本系列例程的根文件系统

https://pan.baidu.com/s/1i5btLGT

opev3.2.0官网源码

https://pan.baidu.com/s/1pLpuHw3

yaffs官网源码 

https://pan.baidu.com/s/1bpkZynt

busybox-1.26.2官网源码

https://pan.baidu.com/s/1i4EtjfR

tslib官网源码

https://pan.baidu.com/s/1i5MGRhb

mplayer-1.3.0官网源码

https://pan.baidu.com/s/1sl0fXlr

基于S3C2416修改的linux-4.10.10源码


0 0