通过前面对platform总线驱动的介绍以及基于platform总线编写的设备驱动代码分析,进一步加深了对platform总线的认识。现在基于驱动代码编写简单驱动测试程序验证驱动代码的正确性。
1.驱动文件
这几个就是程序的源码及所需头文件。
(1)plat_led.c
/*********************************************************************************
* Copyright: (C) 2017 Huang Weiming<710564672@qq.com>
* All rights reserved.
*
* Filename: plat_led.c
* Description: This file
*
* Version: 1.0.0(2017年04月15日)
* Author: Huang Weiming <710564672@qq.com>
* ChangeLog: 1, Release initial version on "2017年04月15日 13时32分10秒"
*
********************************************************************************/
#include "s3c_driver.h"
#define DRV_AUTHOR "Guo Wenxue <guowenxue@gmail.com>"
#define DRV_DESC "S3C24XX LED driver"
/* Driver version*/
#define DRV_MAJOR_VER 1
#define DRV_MINOR_VER 0
#define DRV_REVER_VER 0
#define DEV_NAME DEV_LED_NAME
//#define DEV_MAJOR DEV_LED_MAJOR
#ifndef DEV_MAJOR
#define DEV_MAJOR 0 /* dynamic major by default */
#endif
#define TIMER_TIMEOUT 40
static int debug = DISABLE;
static int dev_major = DEV_MAJOR;
static int dev_minor = 0;
/* ============================ Platform Device part ===============================*/
/* LED hardware informtation structure*/
struct s3c_led_info //LED结构体的定义
{
unsigned char num; /* The LED number */
unsigned int gpio; /* Which GPIO the LED used */
unsigned char active_level; /* The GPIO pin level(HIGHLEVEL or LOWLEVEL) to turn on or off */
unsigned char status; /* Current LED status: OFF/ON */
unsigned char blink; /* Blink or not */
};
/* The LED platform device private data structure */
struct s3c_led_platform_data //总线的定义
{
struct s3c_led_info *leds;
int nleds;
};
/* LED hardware informtation data*/
static struct s3c_led_info s3c_leds[] = { //LED灯的信息
[0] = {
.num = 1,
.gpio = S3C2410_GPB(5),
.active_level = LOWLEVEL,
.status = OFF,
.blink = ENABLE,
},
[1] = {
.num = 2,
.gpio = S3C2410_GPB(6),
.active_level = LOWLEVEL,
.status = OFF,
.blink = DISABLE,
},
[2] = {
.num = 3,
.gpio = S3C2410_GPB(8),
.active_level = LOWLEVEL,
.status = OFF,
.blink = DISABLE,
},
[3] = {
.num = 4,
.gpio = S3C2410_GPB(10),
.active_level = LOWLEVEL,
.status = OFF,
.blink = DISABLE,
},
};
/* The LED platform device private data */
static struct s3c_led_platform_data s3c_led_data = {//定义LED灯的结构体信息
.leds = s3c_leds,//LED灯的每条信息
.nleds = ARRAY_SIZE(s3c_leds),//灯数
};
struct led_device//定义led_device的结构体
{
struct s3c_led_platform_data *data;
struct cdev cdev;
struct class *dev_class;
struct timer_list blink_timer;
} led_device;
static void platform_led_release(struct device * dev)//撤销LED灯的函数
{
int i;
struct s3c_led_platform_data *pdata = dev->platform_data;
dbg_print("%s():%d\n", __FUNCTION__,__LINE__);
/* Turn all LED off */
for(i=0; i<pdata->nleds; i++)
{
s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);
}
}
static struct platform_device s3c_led_device = {//定义设备结构体
.name = "s3c_led",
.id = 1,
.dev =
{
.platform_data = &s3c_led_data,
.release = platform_led_release,
},
};
/* ===================== led device driver part ===========================*/
void led_timer_handler(unsigned long data)
{
int i;
struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data;
for(i=0; i<pdata->nleds; i++)
{
if(ON == pdata->leds[i].status) //判断LED灯的亮灭
{
s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);
}
else
{
s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);
}
if(ENABLE == pdata->leds[i].blink ) /* LED should blink */
{
/* Switch status between 0 and 1 to turn LED ON or off */
pdata->leds[i].status = pdata->leds[i].status ^ 0x01;
}
mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT);//计时器更新,jiffies是全局变量,在头文件
}
}
static int led_open(struct inode *inode, struct file *file)//LED开启函数
{
struct led_device *pdev ;
struct s3c_led_platform_data *pdata;
/*container_of 在Linux内核中是一个常用的宏,用于从包