1.在内核模块中启用定时器,定时1s,让led1—秒亮、一秒灭
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
struct device_node *dnode;
struct gpio_desc* gpiono;
struct timer_list mytimer;
void timer_callback(struct timer_list* mytimer)
{
if(gpiod_get_value(gpiono) == 0)
{
//亮灯
gpiod_set_value(gpiono,1);
mod_timer(mytimer,jiffies+HZ);
}
else if(gpiod_get_value(gpiono) == 1)
{
//灭灯
gpiod_set_value(gpiono,0);
mod_timer(mytimer,jiffies+HZ);
}
}
static int __init mycdev_init(void)
{
//初始化定时器
mytimer.expires = jiffies+HZ;
timer_setup(&mytimer,timer_callback,0);
//解析设备树节点信息
dnode = of_find_node_by_path("/myleds");
if(dnode == NULL)
{
printk("解析设备树节点信息失败\n");
return -1;
}
printk("解析设备树节点信息成功\n");
//申请gpio
gpiono = gpiod_get_from_of_node(dnode,"led1",0,GPIOD_OUT_LOW,NULL);
if(IS_ERR(gpiono))
{
printk("申请gpio失败\n");
return -PTR_ERR(gpiono);
}
printk("申请gpio成功\n");
add_timer(&mytimer);
//设置gpio输出高电平,灯亮
gpiod_set_value(gpiono,1);
return 0;
}
static void __exit mycdev_exit(void)
{
//灯灭
gpiod_set_value(gpiono,0);
//释放gpio编号
gpiod_put(gpiono);
del_timer(&mytimer);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
2.基于gpio子系统完成LED灯驱动的注册,应用程序测试
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#define LED_ON _IO('l', 1)
#define LED_OFF _IO('l', 0)
#endif
led.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#include "head.h"
unsigned int major; // 主设备号
struct class *cls;
struct device *dev;
struct device_node *dnode;
struct gpio_desc *gpiono1, *gpiono2, *gpiono3;
// 封装操作方法
int myled_open(struct inode *inode, struct file *file)
{
int mi = MINOR(inode->i_rdev);
file->private_data = (void *)mi;
return 0;
}
long myled_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int mi = (int)file->private_data;
switch (mi)
{
case 0: // LED1
switch (cmd)
{
case LED_OFF:
gpiod_set_value(gpiono1, 0);
break;
case LED_ON:
gpiod_set_value(gpiono1, 1);
break;
}
break;
case 1: // LED2
switch (cmd)
{
case LED_OFF:
gpiod_set_value(gpiono2, 0);
break;
case LED_ON:
gpiod_set_value(gpiono2, 1);
break;
}
break;
case 2: // LED3
switch (cmd)
{
case LED_OFF:
gpiod_set_value(gpiono3, 0);
break;
case LED_ON:
gpiod_set_value(gpiono3, 1);
break;
}
break;
}
return 0;
}
int myled_close(struct inode *inode, struct file *file)
{
return 0;
}
struct file_operations fops =
{
.open = myled_open,
.unlocked_ioctl = myled_ioctl,
.release = myled_close,
};
static int __init mycdev_init(void)
{
int i;
// 字符设备驱动注册
major = register_chrdev(0, "led", &fops);
if (major < 0)
{
printk("字符设备驱动注册失败\n");
return major;
}
// 向上提交设备节点目录
cls = class_create(THIS_MODULE, "led");
if (IS_ERR(cls))
{
printk("向上提交设备节点目录失败\n");
return -PTR_ERR(cls);
}
// 向上提交设备节点信息
for (i = 0; i < 3; i++)
{
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "led%d", i);
if (IS_ERR(dev))
{
printk("向上提交设备节点信息失败\n");
return -PTR_ERR(dev);
}
}
// 解析设备树节点信息
dnode = of_find_node_by_path("/myleds");
if (dnode == NULL)
{
printk("解析设备树节点信息失败\n");
return -1;
}
// 根据设备树节点信息解析led1 gpio结构体并向内核中注册
gpiono1 = gpiod_get_from_of_node(dnode, "led1", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(gpiono1))
{
printk("申请gpio失败\n");
return -PTR_ERR(gpiono1);
}
// 根据设备树节点信息解析led2 gpio结构体并向内核中注册
gpiono2 = gpiod_get_from_of_node(dnode, "led2", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(gpiono2))
{
printk("申请gpio失败\n");
return -PTR_ERR(gpiono2);
}
// 根据设备树节点信息解析led3 gpio结构体并向内核中注册
gpiono3 = gpiod_get_from_of_node(dnode, "led3", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(gpiono3))
{
printk("申请gpio失败\n");
return -PTR_ERR(gpiono3);
}
printk("LED准备完成\n");
return 0;
}
static void __exit mycdev_exit(void)
{
int i;
gpiod_set_value(gpiono1, 0);
gpiod_set_value(gpiono2, 0);
gpiod_set_value(gpiono3, 0);
gpiod_put(gpiono1);
gpiod_put(gpiono2);
gpiod_put(gpiono3);
// 注销设备节点信息
for (i = 0; i < 3; i++)
{
device_destroy(cls, MKDEV(major, i));
}
// 注销设备节点目录
class_destroy(cls);
// 注销字符设备驱动
unregister_chrdev(major, "/dev/led");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "head.h"
void do_led(int num)
{
char pathname[128] = "";
int key;
sprintf(pathname, "/dev/led%d", num-1);
int fd = open(pathname, O_RDWR);
if (fd < 0)
{
printf("打开文件失败\n");
return;
}
printf("0(灭灯) 1(亮灯) >");
scanf("%d", &key);
switch (key)
{
case 0:
ioctl(fd, LED_OFF);
break;
case 1:
ioctl(fd, LED_ON);
break;
default:
printf("输入错误\n");
return;
}
close(fd);
}
int main(int argc, const char *argv[])
{
int num;
while (1)
{
printf("请选择要控制的LED灯 1(LED1) 2(LED2) 3(LED3) >");
scanf("%d", &num);
do_led(num);
}
return 0;
}