驱动work8.1

驱动

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>

#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
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 <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值