myleds.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "myled.h"
#define CNAME "myled"
struct cdev *cdev; // cdev结构体指针
dev_t devt; //申请的设备号
int major; //主设备号
int minor = 0; //次设备号
unsigned int count = 6; //设备个数
struct class *cls; //目录句柄,class结构体指针
struct device *dev; // device结构体指针
struct device_node *node;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
struct gpio_desc *gpiono4;
struct gpio_desc *gpiono5;
struct gpio_desc *gpiono6;
// open函数
int mycdev_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
// ioctl函数
long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret, which;
switch (cmd)
{
case LED_ON:
ret = copy_from_user(&which, (void *)arg, sizeof(int));
if (ret)
{
printk("copy from user ledon error\n");
return -EIO;
}
switch (which)
{
case 1:
gpiod_set_value(gpiono1, 1);
break;
case 2:
gpiod_set_value(gpiono2, 1);
break;
case 3:
gpiod_set_value(gpiono3, 1);
break;
case 4:
gpiod_set_value(gpiono4, 1);
break;
case 5:
gpiod_set_value(gpiono5, 1);
break;
case 6:
gpiod_set_value(gpiono6, 1);
break;
}
break;
case LED_OFF:
ret = copy_from_user(&which, (void *)arg, sizeof(int));
if (ret)
{
return -EIO;
}
switch (which)
{
case 1:
gpiod_set_value(gpiono1, 0);
break;
case 2:
gpiod_set_value(gpiono2, 0);
break;
case 3:
gpiod_set_value(gpiono3, 0);
break;
case 4:
gpiod_set_value(gpiono4, 0);
break;
case 5:
gpiod_set_value(gpiono5, 0);
break;
case 6:
gpiod_set_value(gpiono6, 0);
break;
}
break;
}
return 0;
}
// close函数
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
//操作方法结构体初始化
const struct file_operations fops = {
.open = mycdev_open,
.unlocked_ioctl = ioctl,
.release = mycdev_close,
};
//入口函数
static int __init mycdev_init(void)
{
int ret, i;
// 1.分配字符设备驱动
cdev = cdev_alloc();
if(cdev == NULL)
{
printk("cdev alloc failed\n");
goto ERR1;
}
printk("cdev alloc success\n");
// 2.设备驱动初始化
cdev_init(cdev, &fops);
// 3.申请设备号
ret = alloc_chrdev_region(&devt, minor, count, CNAME);
if (ret)
{
printk("alloc chrdev region failed\n");
goto ERR2;
}
printk("alloc chrdev region success\n");
//获取主设备号
major = MAJOR(devt);
//获取次设备号
minor = MINOR(devt);
// 4.注册字符设备驱动
ret = cdev_add(cdev,MKDEV(major,minor), count);
if (ret)
{
printk("add is failed\n");
goto ERR3;
}
// 5.自动创建设备节点
//向上提交节点目录
cls = class_create(THIS_MODULE, CNAME);
if (IS_ERR(cls))
{
printk("up submit dir failed\n");
return PTR_ERR(cls);
goto ERR4;
}
printk("up submit dir success\n");
//创建设备节点
for (i = 0; i < 6; i++)
{
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
if (IS_ERR(dev))
{
printk("create jiedian failed\n");
ret = PTR_ERR(dev);
goto ERR5;
}
}
printk("create jiedian success\n");
//通过名字获取设备树节点信息
node = of_find_node_by_name(NULL, "myled");
if (node == NULL)
{
printk("通过名字解析设备树节点失败\n");
return -EFAULT;
}
printk("成功解析到设备树节点\n");
//获取并申请gpio编号
gpiono1 = gpiod_get_from_of_node(node, "myled1", 0, GPIOD_OUT_LOW, NULL);
gpiono2 = gpiod_get_from_of_node(node, "myled2", 0, GPIOD_OUT_LOW, NULL);
gpiono3 = gpiod_get_from_of_node(node, "myled3", 0, GPIOD_OUT_LOW, NULL);
gpiono4 = gpiod_get_from_of_node(node, "myled4", 0, GPIOD_OUT_LOW, NULL);
gpiono5 = gpiod_get_from_of_node(node, "myled5", 0, GPIOD_OUT_LOW, NULL);
gpiono6 = gpiod_get_from_of_node(node, "myled6", 0, GPIOD_OUT_LOW, NULL);
printk("获取gpio编号成功\n");
//设置管脚为输出
gpiod_direction_output(gpiono1, 0);
gpiod_direction_output(gpiono2, 0);
gpiod_direction_output(gpiono3, 0);
gpiod_direction_output(gpiono4, 0);
gpiod_direction_output(gpiono5, 0);
gpiod_direction_output(gpiono6, 0);
return 0;
ERR5:
for (--i; i >= 0; i--)
{
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev);
ERR3:
unregister_chrdev_region(MKDEV(major, minor), count);
ERR2:
kfree(cdev);
ERR1:
return -ENOMEM;
}
//出口函数
static void __exit mycdev_exit(void)
{
int i;
// 1.销毁设备节点
for (i = 0; i < count; i++)
{
device_destroy(cls, MKDEV(major, i));
}
// 2.销毁目录信息
class_destroy(cls);
// 3.注销字符设备驱动
cdev_del(cdev);
// 4.释放设备号
unregister_chrdev_region(MKDEV(major, minor), count);
// 5.释放动态申请的空间
kfree(cdev);
// 6.释放申请的gpio编号
gpiod_put(gpiono1);
gpiod_put(gpiono2);
gpiod_put(gpiono3);
gpiod_put(gpiono4);
gpiod_put(gpiono5);
gpiod_put(gpiono6);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
// GPL协议
MODULE_LICENSE("GPL");
myled.h
#ifndef __MYLED_H__
#define __MYLED_H__
enum LED
{
LED1 = 1,
LED2,
LED3,
};
#define LED_ON _IOW('a', 1, int)
#define LED_OFF _IOW('a', 0, int)
#endif
test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "myled.h"
int main(int argc, char const *argv[])
{
int which;
int fd1 = open("/dev/myled0", O_RDWR);
if (-1 == fd1)
{
perror("open is error\n");
exit(1);
}
int fd2 = open("/dev/myled1", O_RDWR);
if (-1 == fd2)
{
perror("open is error\n");
exit(1);
}
int fd3 = open("/dev/myled2", O_RDWR);
if (-1 == fd3)
{
perror("open is error\n");
exit(1);
}
int fd4 = open("/dev/myled3", O_RDWR);
if (-1 == fd4)
{
perror("open is error\n");
exit(1);
}
int fd5 = open("/dev/myled4", O_RDWR);
if (-1 == fd5)
{
perror("open is error\n");
exit(1);
}
int fd6 = open("/dev/myled5", O_RDWR);
if (-1 == fd6)
{
perror("open is error\n");
exit(1);
}
while (1)
{
which = 1;
ioctl(fd1, LED_ON, &which);
sleep(1);
ioctl(fd1, LED_OFF, &which);
sleep(1);
which = 2;
ioctl(fd2, LED_ON, &which);
sleep(1);
ioctl(fd2, LED_OFF, &which);
sleep(1);
which = 3;
ioctl(fd3, LED_ON, &which);
sleep(1);
ioctl(fd3, LED_OFF, &which);
sleep(1);
which = 4;
ioctl(fd4, LED_ON, &which);
sleep(1);
ioctl(fd4, LED_OFF, &which);
sleep(1);
which = 5;
ioctl(fd5, LED_ON, &which);
sleep(1);
ioctl(fd5, LED_OFF, &which);
sleep(1);
which = 6;
ioctl(fd6, LED_ON, &which);
sleep(1);
ioctl(fd6, LED_OFF, &which);
sleep(1);
}
close(fd1);
close(fd2);
close(fd3);
close(fd4);
close(fd5);
close(fd6);
return 0;
}
六盏灯流水灯点亮