驱动
#include
#include
#include
#include
#include
#include
#include
#include
#include
unsigned int major; // 定义一个变量保存主设备号
struct class *cls;
struct device *cdev;
// 定义设备节点信息指针
struct device_node *dev;
// 定义对象指针,led
struct gpio_desc *gpiono1, *gpiono2, *gpiono3;
// 中断部分
unsigned int irqno1, irqno2, irqno3;
unsigned int flag;
// 中断处理函数
irqreturn_t myirq_fun1(int irq, void *dev)
{
// 获取灯的当前状态
flag = gpiod_get_value(gpiono1);
// 控制led灯逻辑
gpiod_set_value(gpiono1, !flag);
return IRQ_HANDLED;
}
irqreturn_t myirq_fun2(int irq, void *dev)
{
// 获取灯的当前状态
flag = gpiod_get_value(gpiono2);
// 控制led灯逻辑
gpiod_set_value(gpiono2, !flag);
return IRQ_HANDLED;
}
irqreturn_t myirq_fun3(int irq, void *dev)
{
// 获取灯的当前状态
flag = gpiod_get_value(gpiono3);
// 控制led灯逻辑
gpiod_set_value(gpiono3, !flag);
return IRQ_HANDLED;
}
// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
// ioctrl
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case 1: // led1灯
// 获取灯的当前状态
flag = gpiod_get_value(gpiono1);
// 控制led灯逻辑
gpiod_set_value(gpiono1, !flag);
break;
case 2: // led2灯
// 获取灯的当前状态
flag = gpiod_get_value(gpiono2);
// 控制led灯逻辑
gpiod_set_value(gpiono2, !flag);
break;
case 3: // led3灯
// 获取灯的当前状态
flag = gpiod_get_value(gpiono3);
// 控制led灯逻辑
gpiod_set_value(gpiono3, !flag);
break;
default:
break;
}
return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
// 定义一个操作方法结构体变量并且初始化
struct file_operations fops = {
.open = mycdev_open,
.release = mycdev_close,
.unlocked_ioctl = mycdev_ioctl,
};
static int __init mycdev_init(void)
{
//==字符设备驱动部分============================================================================================================
// 注册字符设备驱动
major = register_chrdev(0, "mychrdev", &fops);
if (major < 0)
{
printk("注册字符设备驱动失败\n");
return major;
}
printk("注册字符设备驱动成功major=%d\n", major);
// 向上提交目录
cls = class_create(THIS_MODULE, "myled");
if (IS_ERR(cls))
{
printk("向上创建目录失败!\n");
return -PTR_ERR(cls);
}
printk("向上创建目录成功!\n");
// 向上提交节点
cdev = device_create(cls, NULL, MKDEV(major, 0), NULL, "myled");
if (IS_ERR(cdev))
{
printk("向上提交节点失败!\n");
return -PTR_ERR(cdev);
}
printk("向上提交节点成功!\n");
//==字符设备驱动部分============================================================================================================
// 解析设备树节点信息
dev = of_find_node_by_path("/myled");
if (dev == NULL)
{
return -EFAULT;
}
printk("LED部分解析成功!/n");
//==LED子系统==================================================================================================================
// 申请对象并设置输出位低电平
gpiono1 = gpiod_get_from_of_node(dev, "led1-gpios", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(gpiono1))
{
printk("gpiono1申请失败!\n");
return -PTR_ERR(gpiono1);
}
gpiono2 = gpiod_get_from_of_node(dev, "led2-gpios", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(gpiono2))
{
printk("gpiono2申请失败!\n");
return -PTR_ERR(gpiono2);
}
gpiono3 = gpiod_get_from_of_node(dev, "led3-gpios", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(gpiono3))
{
printk("gpiono3申请失败!\n");
return -PTR_ERR(gpiono3);
}
printk("LED部分申请成功!/n");
//==LED子系统==================================================================================================================
//==中断子系统==================================================================================================================
int ret;
dev = of_find_node_by_path("/myirq");
if (dev == NULL)
{
return -EFAULT;
}
printk("IRQ部分解析成功!/n");
// 解析软中断号
irqno1 = irq_of_parse_and_map(dev, 0);
if (!irqno1)
{
return -ENXIO;
}
irqno2 = irq_of_parse_and_map(dev, 1);
if (!irqno2)
{
return -ENXIO;
}
irqno3 = irq_of_parse_and_map(dev, 2);
if (!irqno3)
{
return -ENXIO;
}
printk("IRQ部分申请成功!/n");
// 注册中断
ret = request_irq(irqno1, myirq_fun1, IRQF_TRIGGER_FALLING, "key1", NULL);
if (ret)
{
return ret;
}
ret = request_irq(irqno2, myirq_fun2, IRQF_TRIGGER_FALLING, "key2", NULL);
if (ret)
{
return ret;
}
ret = request_irq(irqno3, myirq_fun3, IRQF_TRIGGER_FALLING, "key3", NULL);
if (ret)
{
return ret;
}
//==中断子系统==================================================================================================================
return 0;
}
static void __exit mycdev_exit(void)
{
// 销毁节点信息
device_destroy(cls, MKDEV(major, 0));
// 销毁目录信息
class_destroy(cls);
// 注销字符设备驱动
unregister_chrdev(major, "mychrdev");
// 关闭led灯
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);
// 注销中断
free_irq(irqno1, NULL);
free_irq(irqno2, NULL);
free_irq(irqno3, NULL);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
main
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
int led_fd = open("/dev/myled", O_RDWR);
if (led_fd < 0)
{
printf("打开设备文件失败\n");
exit(-1);
}
while (1)
{
printf("请输入要操作的灯(1-LED1 2-LED2 3-LED3)>>>");
int flag;
scanf("%d", &flag);
ioctl(led_fd, flag);
}
close(led_fd);
return 0;
}