- 1.在内核模块中启用定时器,定时1s,让led1 一秒亮、一秒灭
#include <linux/init.h>
#include <linux/module.h>
#include<linux/of.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>
#include<linux/timer.h>
/*
myleds{
led1=<&gpioe 10 0>;
led2=<&gpiof 10 0>;
led3=<&gpioe 8 0>;
};
*/
struct device_node *dnode;
struct gpio_desc *gpiono;
struct timer_list mytimer;
void mytimer_func(struct timer_list *timer)
{
if(gpiod_get_value(gpiono) == 0)
{
//亮灯
gpiod_set_value(gpiono,1);
mod_timer(timer,jiffies+HZ);
}
else if(gpiod_get_value(gpiono) == 1)
{
//灭灯
gpiod_set_value(gpiono,0);
mod_timer(timer,jiffies+HZ);
}
}
static int __init mycdev_init(void)
{
int ret;
//初始化定时器对象
mytimer.expires=jiffies+HZ;
timer_setup(&mytimer,mytimer_func,0);
//解析led灯的设备树节点
dnode=of_find_node_by_path("/myleds");
if(dnode==NULL)
{
printk("解析设备树节点失败\n");
return -ENXIO;
}
printk("解析设备树节点成功\n");
//根据设备树节点解析led1 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);
}
//将定时器对象注册进内核
add_timer(&mytimer);
//亮灯
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灯驱动的注册,应用程序测试
- myled.c
-
#include <linux/init.h> #include <linux/module.h> #include<linux/of.h> #include<linux/gpio.h> #include<linux/of_gpio.h> #include<linux/timer.h> struct { char led_num; int led_type; }led; /* myleds{ led1=<&gpioe 10 0>; led2=<&gpiof 10 0>; led3=<&gpioe 8 0>; }; */ struct class *cla; struct device *dev; int major;//用于保存主设备号 struct device_node *dnode; struct gpio_desc *gpiono1, *gpiono2, *gpiono3; struct timer_list mytimer; // 定义计时器对象 int mycdev_open(struct inode *inode, struct file *file) { printk("%s:%s:%d\n", __FILE__, __func__, __LINE__); return 0; } ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff) { int ret; ret = copy_from_user(&led,ubuf, size); if (ret) { printk("copy_from_user filed\n"); return -EIO; } printk("type = %c\n", led.led_num); printk("num = %d\n", led.led_type); if (led.led_num == 'a') { if (led.led_type == 1) // 开灯 { gpiod_set_value(gpiono1, 1); } else if (led.led_type == 0) // 关灯 { gpiod_set_value(gpiono1, 0); } } else if (led.led_num == 'b') { if (led.led_type == 1) // 开灯 { gpiod_set_value(gpiono2, 1); } else if (led.led_type == 0) // 关灯 { gpiod_set_value(gpiono2, 0); } } else if (led.led_num == 'c') { if (led.led_type == 1) // 开灯 { gpiod_set_value(gpiono3, 1); } else if (led.led_type == 0) // 关灯 { gpiod_set_value(gpiono3, 0); } } else if (led.led_num == 'd') { if (led.led_type == 1) // 开灯 { gpiod_set_value(gpiono1, 1); gpiod_set_value(gpiono2, 1); gpiod_set_value(gpiono3, 1); } else if (led.led_type == 0) // 关灯 { gpiod_set_value(gpiono1, 0); gpiod_set_value(gpiono2, 0); gpiod_set_value(gpiono3, 0); } } printk("%s:%s:%d\n", __FILE__, __func__, __LINE__); return 0; } // 操作方法结构体的初始化 struct file_operations fops = { .open = mycdev_open, .write = mycdev_write, }; static int __init mycdev_init(void) { int i; // 字符设备驱动注册 major = register_chrdev(0, "mychrdev", &fops); if (major < 0) { printk("字符设备驱动注册失败\n"); return major; } printk("字符设备驱动注册成功major=%d\n", major); // 向上提交目录 cla = class_create(THIS_MODULE, "mychrdev"); if (IS_ERR(cla)) { printk("向上提交目录失败\n"); return -PTR_ERR(cla); } printk("向上提交目录成功\n"); // 向上提交设备节点信息,为三盏灯创建三个设备文件 for (i = 0; i < 3; i++) { dev = device_create(cla, NULL, MKDEV(major, i), NULL, "mychrdev%d", i); if (IS_ERR(dev)) { printk("向上提交设备节点信息失败\n"); return -PTR_ERR(dev); } printk("向上提交设备节点%d信息成功\n", i); } // 解析led灯的设备树节点 dnode = of_find_node_by_path("/myleds"); if (dnode == NULL) { printk("解析设备树节点失败\n"); return -ENXIO; } printk("解析设备树节点成功\n"); // 根据设备树节点解析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); } gpiono2 = gpiod_get_from_of_node(dnode, "led2", 0, GPIOD_OUT_LOW, NULL); if (IS_ERR(gpiono2)) { gpiod_put(gpiono1); printk("申请gpio失败\n"); return -PTR_ERR(gpiono2); } gpiono3 = gpiod_get_from_of_node(dnode, "led3", 0, GPIOD_OUT_LOW, NULL); if (IS_ERR(gpiono3)) { gpiod_put(gpiono1); gpiod_put(gpiono2); printk("申请gpio失败\n"); return -PTR_ERR(gpiono3); } // 亮灯 gpiod_set_value(gpiono1, 1); gpiod_set_value(gpiono2, 1); gpiod_set_value(gpiono3, 1); 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); // 注销gpio信息 gpiod_put(gpiono1); gpiod_put(gpiono2); gpiod_put(gpiono3); // 销毁设备节点信息 for (i = 0; i < 3; i++) { device_destroy(cla, MKDEV(major, i)); } class_destroy(cla); // 字符设备驱动的注销 unregister_chrdev(major, "mychrdev"); } module_init(mycdev_init); module_exit(mycdev_exit); MODULE_LICENSE("GPL");
test.c
-
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> struct { char led_num; int led_type; }led; int main(int argc, char const *argv[]) { int fd = open("/dev/mychrdev0", O_RDWR); if (fd < 0) { printf("打开设备文件失败\n"); exit(-1); } while (1) { LOOP: printf("请选择灯(a(key1) b(key2) c(key3) d(all led) q(Quit)"); scanf("%c", &led.led_num); if(led.led_num < 'a' || led.led_num > 'd' && led.led_num != 'q') { printf("输入错误,请重新输入!!!\n"); goto LOOP; } getchar(); if(led.led_num == 'q') break; printf("请选择灯的亮灭(0:关灯 1:开灯): "); scanf("%d", &led.led_type); if(led.led_type != 1 && led.led_type != 0) { printf("输入错误,请重新输入!!!\n"); goto LOOP; } getchar(); write(fd, &led, sizeof(led)); } close(fd); return 0; }