华清远见上海中心22071班
使用ioctl,GPIO子系统控制LED灯
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "linux_6led.h"
#define CNAME "myled"
int major;
int minor = 0;
int count = 6;
struct cdev *cdev;
struct class *cls;
struct device *dvc;
struct device_node *node;
struct gpio_desc *topled1;
struct gpio_desc *topled2;
struct gpio_desc *topled3;
struct gpio_desc *baseled1;
struct gpio_desc *baseled2;
struct gpio_desc *baseled3;
// myleds
// {
// topled1 = <&gpioe 10 0>;
// topled2 = <&gpiof 10 0>;
// topled3 = <&gpioe 8 0>;
// baseled1 = <&gpioz 5 0>;
// baseled2 = <&gpioz 6 0>;
// baseled3 = <&gpioz 7 0>;
// };
int mycdev_open(struct inode *inode, struct file *file)
{
printk("打开成功\n");
return 0;
}
int mycdev_release(struct inode *inode, struct file *file)
{
printk("关闭成功\n");
return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case TOPLED1_ON:
gpiod_set_value(topled1, 1);
break;
case TOPLED1_OFF:
gpiod_set_value(topled1, 0);
break;
case TOPLED2_ON:
gpiod_set_value(topled2, 1);
break;
case TOPLED2_OFF:
gpiod_set_value(topled2, 0);
break;
case TOPLED3_ON:
gpiod_set_value(topled3, 1);
break;
case TOPLED3_OFF:
gpiod_set_value(topled3, 0);
break;
case BASELED1_ON:
gpiod_set_value(baseled1, 1);
break;
case BASELED1_OFF:
gpiod_set_value(baseled1, 0);
break;
case BASELED2_ON:
gpiod_set_value(baseled2, 1);
break;
case BASELED2_OFF:
gpiod_set_value(baseled2, 0);
break;
case BASELED3_ON:
gpiod_set_value(baseled3, 1);
break;
case BASELED3_OFF:
gpiod_set_value(baseled3, 0);
break;
}
return 0;
}
struct file_operations fops = {
.open = mycdev_open,
.release = mycdev_release,
.unlocked_ioctl = mycdev_ioctl};
static int __init
led_init(void)
{
int res, i;
dev_t devt;
//分配cdev结构
cdev = cdev_alloc();
if (NULL == cdev)
{
printk("申请空间失败\n");
res = -EIO;
goto ERR1;
}
//初始化cdev结构体
cdev_init(cdev, &fops);
//动态注册字符设备编号
res = alloc_chrdev_region(&devt, 0, count, CNAME);
if (res)
{
printk("动态注册字符设备编号失败(err %d)\n", -res);
goto ERR2;
}
major = MAJOR(devt);
minor = MINOR(devt);
//向系统中添加字符设备
res = cdev_add(cdev, devt, count);
if (res)
{
printk("系统添加字符设备失败(err %d)\n", -res);
goto ERR3;
}
//上传目录
cls = class_create(THIS_MODULE, CNAME);
if (IS_ERR(cls))
{
printk("上传目录失败 (err %ld)\n", PTR_ERR(cls));
res = PTR_ERR(cls);
goto ERR4;
}
//上传节点
for (i = 0; i < count; i++)
{
dvc = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
if (IS_ERR(dvc))
{
printk("节点上传失败 (err %ld)\n", PTR_ERR(dvc));
res = PTR_ERR(dvc);
goto ERR5;
}
}
node = of_find_node_by_path("/myleds");
if (NULL == node)
{
printk("寻找设备树节点失败\n");
res = -EFAULT;
goto ERR5;
}
//申请GPIO号
topled1 = gpiod_get_from_of_node(node, "topled1", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(topled1))
{
printk("topled1 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled1));
res = PTR_ERR(topled1);
goto ERR5;
}
topled2 = gpiod_get_from_of_node(node, "topled2", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(topled2))
{
printk("topled2 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled2));
res = PTR_ERR(topled2);
goto ERR5;
}
topled3 = gpiod_get_from_of_node(node, "topled3", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(topled3))
{
printk("topled3 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled3));
res = PTR_ERR(topled3);
goto ERR5;
}
baseled1 = gpiod_get_from_of_node(node, "baseled1", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(baseled1))
{
printk("baseled1 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(baseled1));
res = PTR_ERR(baseled1);
goto ERR5;
}
baseled2 = gpiod_get_from_of_node(node, "baseled2", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(baseled2))
{
printk("baseled2 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(baseled2));
res = PTR_ERR(baseled2);
goto ERR5;
}
baseled3 = gpiod_get_from_of_node(node, "baseled3", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(topled3))
{
printk("baseled3 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(baseled3));
res = PTR_ERR(baseled3);
goto ERR5;
}
//设置相对应的gpio引脚为输出模式
gpiod_direction_output(topled1, 0);
gpiod_direction_output(topled2, 0);
gpiod_direction_output(topled3, 0);
gpiod_direction_output(baseled1, 0);
gpiod_direction_output(baseled2, 0);
gpiod_direction_output(baseled3, 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(devt, count);
ERR2:
kfree(cdev);
ERR1:
return res;
}
static void __exit led_exit(void)
{
int i;
gpiod_set_value(topled1, 0);
gpiod_set_value(topled2, 0);
gpiod_set_value(topled3, 0);
gpiod_set_value(baseled1, 0);
gpiod_set_value(baseled2, 0);
gpiod_set_value(baseled3, 0);
gpiod_put(topled1);
gpiod_put(topled2);
gpiod_put(topled3);
gpiod_put(baseled1);
gpiod_put(baseled2);
gpiod_put(baseled3);
for (i = 0; i < count; i++)
{
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
cdev_del(cdev);
unregister_chrdev_region(MKDEV(major, minor), count);
kfree(cdev);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "linux_6led.h"
int main(int argc, const char *argv[])
{
int fd1 = open("/dev/myled0", O_RDWR);
if (-1 == fd1)
{
perror("open");
return -1;
}
int fd2 = open("/dev/myled1", O_RDWR);
if (-1 == fd2)
{
perror("open");
return -1;
}
int fd3 = open("/dev/myled2", O_RDWR);
if (-1 == fd3)
{
perror("open");
return -1;
}
int fd4 = open("/dev/myled3", O_RDWR);
if (-1 == fd4)
{
perror("open");
return -1;
}
int fd5 = open("/dev/myled4", O_RDWR);
if (-1 == fd5)
{
perror("open");
return -1;
}
int fd6 = open("/dev/myled5", O_RDWR);
if (-1 == fd6)
{
perror("open");
return -1;
}
while (1)
{
ioctl(fd1, TOPLED1_ON);
sleep(1);
ioctl(fd1, TOPLED1_OFF);
sleep(1);
ioctl(fd2, TOPLED2_ON);
sleep(1);
ioctl(fd2, TOPLED2_OFF);
sleep(1);
ioctl(fd3, TOPLED3_ON);
sleep(1);
ioctl(fd3, TOPLED3_OFF);
sleep(1);
ioctl(fd4, BASELED1_ON);
sleep(1);
ioctl(fd4, BASELED1_OFF);
sleep(1);
ioctl(fd5, BASELED2_ON);
sleep(1);
ioctl(fd5, BASELED2_OFF);
sleep(1);
ioctl(fd6, BASELED3_ON);
sleep(1);
ioctl(fd6, BASELED3_OFF);
}
return 0;
}
#ifndef __LINUX_6LED_H__
#define __LINUX_6LED_H__
#define TOPLED1_ON _IOW('a', 1, int)
#define TOPLED1_OFF _IOW('a', 0, int)
#define TOPLED2_ON _IOW('b', 1, int)
#define TOPLED2_OFF _IOW('b', 0, int)
#define TOPLED3_ON _IOW('c', 1, int)
#define TOPLED3_OFF _IOW('c', 0, int)
#define BASELED1_ON _IOW('d', 1, int)
#define BASELED1_OFF _IOW('d', 0, int)
#define BASELED2_ON _IOW('e', 1, int)
#define BASELED2_OFF _IOW('e', 0, int)
#define BASELED3_ON _IOW('f', 1, int)
#define BASELED3_OFF _IOW('f', 0, int)
#endif