基于gpio子系统编写LED灯的驱动,编写应用程序测试
led.c
#include
#include
#include
#include
#include
#include
#include
#include "head.h"
struct gpio_desc *led_gpios[3];
unsigned int major = 0;
unsigned int minor = 0;
char *devname = "led";
int dfnum = 3; // 驱动文件数量
struct cdev *cdev;
struct class *cls;
struct device *dev;
void led_on_off(int count, unsigned int flag)
{
switch (flag)
{
case LEDX_OFF:
gpiod_set_value(led_gpios[count], 0);
break;
case LEDX_ON:
gpiod_set_value(led_gpios[count], 1);
break;
case LEDX_REV:
gpiod_set_value(led_gpios[count], !gpiod_get_value(led_gpios[count]));
break;
}
}
// 封装操作方法
int led_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
file->private_data = (void *)MINOR(inode->i_rdev);
return 0;
}
ssize_t led_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
return 0;
}
ssize_t led_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
return 0;
}
long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned int min = (int)file->private_data;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
led_on_off(min - minor, cmd);
return 0;
}
int led_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
// 定义一个操作方法结构体对象并且初始化
struct file_operations fops = {
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_close,
.unlocked_ioctl = led_ioctl,
};
static int __init mycdev_init(void)
{
struct device_node *dnode;
int i, j;
cdev = cdev_alloc();
if (!cdev)
{
printk("字符设备驱动对象申请空间失败\n");
goto out1;
}
printk("字符设备驱动对象申请空间成功\n");
cdev_init(cdev, &fops);
if (major)
{
if (register_chrdev_region(MKDEV(major, minor), dfnum, devname))
{
printk("静态申请设备号失败\n");
goto out2;
}
printk("静态申请设备号成功\n");
}
else
{
unsigned int dnub;
if (alloc_chrdev_region(&dnub, minor, dfnum, devname))
{
printk("动态申请设备号失败\n");
goto out2;
}
printk("动态申请设备号成功\n");
major = MAJOR(dnub);
}
if (cdev_add(cdev, MKDEV(major, minor), dfnum))
{
printk("注册驱动失败\n");
goto out3;
}
printk("注册驱动成功\n");
cls = class_create(THIS_MODULE, devname);
if (IS_ERR(cls))
{
printk("向上提交目录失败\n");
goto out4;
}
printk("向上提交目录成功\n");
for (i = 0; i < dfnum; i++)
{
dev = device_create(cls, NULL, MKDEV(major, minor + i), NULL, "%s%d", devname, i);
if (IS_ERR(cls))
{
printk("向上提交设备节点信息失败\n");
goto out5;
}
printk("向上提交设备节点信息成功\n");
}
dnode = of_find_node_by_name(NULL, "myled");
if (dnode == NULL)
{
printk("设备树节点解析失败\n");
goto out5;
}
printk("设备树节点解析成功\n");
for (j = 0; j < 3; j++)
{
led_gpios[j] = gpiod_get_from_of_node(dnode, "led-gpios", j, GPIOD_OUT_LOW, NULL);
if (IS_ERR(led_gpios[j]))
{
printk("解析GPIO失败\n");
goto out6;
}
printk("解析GPIO成功\n");
gpiod_set_value(led_gpios[j], 1);
}
return 0;
out6:
for (j--; j >= 0; j--)
{
gpiod_put(led_gpios[j]);
}
out5:
for (i--; i >= 0; i--)
{
device_destroy(cls, MKDEV(major, minor + i));
}
class_destroy(cls);
out4:
cdev_del(cdev);
out3:
unregister_chrdev_region(MKDEV(major, minor), dfnum);
out2:
kfree(cdev);
out1:
return -1;
}
static void __exit mycdev_exit(void)
{
int i;
del_timer(&timer);
for (i = 0; i < 3; i++)
{
gpiod_set_value(led_gpios[i], 0);
gpiod_put(led_gpios[i]);
device_destroy(cls, MKDEV(major, minor + i));
}
class_destroy(cls);
cdev_del(cdev);
unregister_chrdev_region(MKDEV(major, minor), dfnum);
kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#define LEDX_ON _IO('l',1)
#define LEDX_OFF _IO('l',0)
#define LEDX_REV _IO('l',2)
#endif
test.c
#include
#include
#include
#include
#include "head.h"
int main()
{
int fd[3];
for (int i = 0; i < 3; i++)
{
char path[128] = {0};
snprintf(path, sizeof(path), "/dev/led%d", i);
fd[i] = open(path, O_RDWR);
if (fd[i] < 0)
{
printf("文件打开失败\n");
return -1;
}
}
for (int i = 0;; i++)
{
ioctl(fd[i % 3], LEDX_REV);
sleep(1);
}
for (int i = 0; i < 3; i++)
{
close(fd[i]);
}
return 0;
}