编写LED灯的驱动,创建三个设备文件,每个设备文件和LED灯绑定,当操作这个设备文件时只能控制设备对应的这盏灯

test.c

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "head.h"
#include <sys/ioctl.h>
int main(int argc, char const *argv[])
{
   int a, b; // 控制灯
   int fd, fd_1, fd_2;
   char buf[128] = {0};
   int t;
  
   printf("请输入你要打开哪个灯的设备\n");
   printf("led1:1 led2:2 led3:3>>");
    scanf("%d", &t);
   //while (1)
   //{
      switch (t)
      {
      case 1:
         fd = open("/dev/led0", O_RDWR);
         if (fd < 0)
         {
            printf("打开失败\n");
            return 0;
         }
         while(1)
         {
         printf("1:开灯 0:关灯");
         scanf("%d", &a);
         
         if (a == 1)
         {
            ioctl(fd, LED_ON); // 开灯
         }
         else if (a == 0)
         {
            ioctl(fd, LED_OFF); // 关灯
         }
         }
         break;
         
      case 2:
         fd_1 = open("/dev/led1", O_RDWR);
         if (fd_1 < 0)
         {
            printf("打开失败\n");
            return 0;
         }
         while(1)
         {
          printf("1:开灯 0:关灯");
         scanf("%d", &a);
        
         if (a== 1)
         {
            ioctl(fd_1, LED_ON); // 开灯
         }
         else if (a == 0)
         {
            ioctl(fd_1, LED_OFF); // 关灯
         }
         }
         break;

      case 3:
         fd_2 = open("/dev/led2", O_RDWR);
         if (fd_2 < 0)
         {
            printf("打开失败\n");
            return 0;
         }
         while(1)
         {
       printf("1:开灯 0:关灯");
         scanf("%d", &a);
      
         if (a == 1)
         {
            ioctl(fd_2, LED_ON); // 开灯
         }
         else if (a == 0)
         {
            ioctl(fd_2, LED_OFF); // 关灯
         }
      }
         break;
      }
   //}
   close(fd);
   close(fd_1);
   close(fd_2);
   return 0;
}

head.h

#ifndef __HEAD_H__
#define __HEAD_H__

typedef struct
{
    unsigned int MODER;
    unsigned int OTYPER;
    unsigned int OSPEEDR;
    unsigned int PUPDR;
    unsigned int IDR;
    unsigned int ODR;
}gpio_t;
#define PHY_LED1_ADDR 0x50006000  //GPIOE
#define PHY_LED2_ADDR 0x50007000  //GPIOF
#define PHY_LED3_ADDR 0x50006000
#define PHY_RCC_ADDR  0x50000A28
#define GPIOE         0X50006000
#define GPIOF         0x50007000
#define GPIOB         0x50003000
#define LED_ON   _IO('l',1) //开灯
#define LED_OFF  _IO('l',0) //关机


#endif

LED.C

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include "head.h"
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
struct class *cls;
struct device *dev;
struct cdev *cdev;
dev_t devno;
unsigned int major = 500;
unsigned int minor = 0;
unsigned int *vir_rcc;
int mycdev_open(struct inode *inode, struct file *file)
{
  unsigned int aaa = MINOR(inode->i_rdev); // 得到打开的文件到设备号

  file->private_data = (void *)aaa;
  printk("%s %s %d\n", __FILE__, __func__, __LINE__);
  return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
  unsigned int aaa = (int)file->private_data;
  printk("%s %s %d\n", __FILE__, __func__, aaa);
  switch (aaa)
  {
  case 0:
    // 控制led1的逻辑
    switch (cmd)
    {
    case LED_ON:
    printk("%d   %p\n",__LINE__,vir_led1);
      vir_led1->ODR |= (0x1 << 10);
      break;
    case LED_OFF:
      vir_led1->ODR &= (~(0X1 << 10));
      break;
    }
    break;
  case 1:
    switch (cmd)
    {
    case LED_ON:
      // 控制led2的逻辑
      vir_led2->ODR |= (0x1 << 10);
      break;
    case LED_OFF:
      vir_led2->ODR &= (~(0X1 << 10));
      break;
    }
    break;
  case 2:
    switch (cmd)
    {
    case LED_ON:
      // 控制led3的逻辑
      vir_led3->ODR |= (0x1 << 8);
      break;
    case LED_OFF:
      vir_led3->ODR &= (~(0X1 << 8));
      break;
    }
    break;
  }
  return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{

  printk("%s %s %d", __FILE__, __func__, __LINE__);
  return 0;
}
struct file_operations fops =
    {
        .open = mycdev_open,
        .unlocked_ioctl = mycdev_ioctl,
        .release = mycdev_close,

};
int all_led_init(void)
{
   vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
   if(vir_led1==NULL)
   {
      printk("ioremap filed %d\n",__LINE__);
      return -ENOMEM;
   }
   vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
   if(vir_led2==NULL)
   {
      printk("ioremap filed %d\n",__LINE__);
      return -ENOMEM;
   }
   vir_led3=ioremap(PHY_LED3_ADDR,sizeof(gpio_t));
   if(vir_led3==NULL)
   {
      printk("ioremap filed %d\n",__LINE__);
      return -ENOMEM;
   }
   vir_rcc =ioremap(PHY_RCC_ADDR,4);
   if(vir_rcc==NULL)
   {
       printk("ioremap filed %d\n",__LINE__);
      return -ENOMEM;
   }
   printk("物理地址映射成功\n");
   //寄存器初始化rcc
   (*vir_rcc)|=(3<<4);
   //led1
   vir_led1->MODER&=(~(0x3<<20));
   vir_led1->MODER|=(1<<20);
   vir_led1->ODR&=(~(1<<10));
      //led2
   vir_led2->MODER&=(~(0x3<<20));
   vir_led2->MODER|=(1<<20);
   vir_led2->ODR&=(~(1<<10));
      //led3
   vir_led3->MODER&=(~(0x3<<16));
   vir_led3->MODER|=(1<<16);
   vir_led3->ODR&=(~(1<<8));
   printk("寄存器初始化成功\n");
   return 0;
}
static int __init mycdev_init(void)
{
  int ret, i;
  // 1.分配字符设备驱动对象空间 cdev_alloc
  cdev = cdev_alloc();
  if (cdev == NULL)
  {
    printk("申请字符设备驱动对象空间失败\n");
    ret = -EFAULT;
    goto out1;
  }
  printk("字符设备驱动对象申请成功\n");
  // 2.字符设备驱动对象部分初始化 cdev_init
  cdev_init(cdev, &fops);

  // 3.申请设备号 register_chrdev_region/alloc_chrdev_region
  if (major > 0) // 静态申请设备号
  {
    ret = register_chrdev_region(MKDEV(major, minor), 3, "led");
    if (ret)
    {
      printk("静态指定设备号失败\n");
      goto out2;
    }
  }
  else // 动态申请设备号
  {
    ret = alloc_chrdev_region(&devno, minor, 3, "led");
    if (ret)
    {
      printk("动态申请设备号失败\n");
      goto out2;
    }
    major = MAJOR(devno); // 根据设备号得到主设备号
    minor = MINOR(devno); // 根据设备号得到次设备号
  }
  printk("申请设备号成功\n");
  // 4.注册字符设备驱动对象 cdev_add()
  ret = cdev_add(cdev, MKDEV(major, minor), 3);

  if (ret)
  {
    printk("注册字符设备驱动对象失败\n");
    goto out3;
  }
  printk("注册字符设备驱动对象成功\n");

  // 5.向上提交目录
  cls = class_create(THIS_MODULE, "led");
  if (IS_ERR(cls))
  {
    printk("向上提交目录失败\n");
    return -PTR_ERR(cls);
    goto out4;
  }
  printk("向上提交目录成功\n");
  // 6.向上提交设备节点
  for (i = 0; i < 3; i++)
  {
    dev = device_create(cls, NULL, MKDEV(major, i), NULL, "led%d", i);
    if (IS_ERR(dev))
    {
      printk("向上提交节点信息失败\n");
      ret = -PTR_ERR(dev);
      goto out5;
    }
  }
  printk("向上提交设备节点信息成功\n");
  all_led_init();

  return 0;
out5:
  for (--i; i >= 0; i--)
  {
    // 销毁上面提交的设备信息
    device_destroy(cls, MKDEV(major, i));
  }
  class_destroy(cls);
out4:
  cdev_del(cdev);
out3:
  unregister_chrdev_region(MKDEV(major, minor), 3);
out2:
  kfree(cdev);
out1:
  return ret;
}
static void __exit mycdev_exit(void)
{
  // 销毁设备信息 device_destroy
  int i;
  for (i = 0; i < 3; i++)
  {
    device_destroy(cls, MKDEV(major, i));
  }
  // 销毁目录 class_destroy
  class_destroy(cls);
  // 注销对象 cdev_del()
  cdev_del(cdev);
  // 释放设备号 unregister_chrdev_region()
  unregister_chrdev_region(MKDEV(major, minor), 3);
  // 释放对象空间
  kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Linux设备驱动程序,用于点亮LED。该程序使用了GPIO子系统和字符设备框架。 ```c #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/gpio.h> #include <asm/uaccess.h> #define LED_PIN 17 // 在树莓派上,GPIO17对应的针脚可以用来控制LED static int led_value = 0; // LED的状态,0表示关闭,1表示打开 static dev_t dev_num; // 设备号 static struct class *dev_class; // 设备类别 static struct device *dev; // 设备 // 打开设备 static int led_open(struct inode *inode, struct file *file) { return 0; } // 从设备中读取数据 static ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; } // 向设备中写入数据 static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char kbuf; // 从用户空间中读取一个字节的数据 if (copy_from_user(&kbuf, buf, 1)) return -EFAULT; // 根据读取的数据来控制LED if (kbuf == '0') { gpio_set_value(LED_PIN, 0); led_value = 0; } else if (kbuf == '1') { gpio_set_value(LED_PIN, 1); led_value = 1; } return 1; } // 关闭设备 static int led_release(struct inode *inode, struct file *file) { return 0; } // 设备操作函数 static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, .release = led_release, }; // 初始化设备驱动程序 static int __init led_init(void) { int ret; // 申请GPIO资源 ret = gpio_request(LED_PIN, "LED"); if (ret < 0) { printk(KERN_ERR "Failed to request GPIO %d: %d\n", LED_PIN, ret); return ret; } // 设置GPIO方向为输出 ret = gpio_direction_output(LED_PIN, 0); if (ret < 0) { printk(KERN_ERR "Failed to set GPIO %d direction: %d\n", LED_PIN, ret); gpio_free(LED_PIN); return ret; } // 注册字符设备驱动程序 ret = alloc_chrdev_region(&dev_num, 0, 1, "led"); if (ret < 0) { printk(KERN_ERR "Failed to allocate device number: %d\n", ret); gpio_free(LED_PIN); return ret; } // 创建设备类别 dev_class = class_create(THIS_MODULE, "led"); if (IS_ERR(dev_class)) { printk(KERN_ERR "Failed to create device class\n"); unregister_chrdev_region(dev_num, 1); gpio_free(LED_PIN); return PTR_ERR(dev_class); } // 创建设备 dev = device_create(dev_class, NULL, dev_num, NULL, "led"); if (IS_ERR(dev)) { printk(KERN_ERR "Failed to create device\n"); class_destroy(dev_class); unregister_chrdev_region(dev_num, 1); gpio_free(LED_PIN); return PTR_ERR(dev); } // 注册设备操作函数 cdev_init(&led_cdev, &led_fops); ret = cdev_add(&led_cdev, dev_num, 1); if (ret < 0) { printk(KERN_ERR "Failed to add device to kernel: %d\n", ret); device_destroy(dev_class, dev_num); class_destroy(dev_class); unregister_chrdev_region(dev_num, 1); gpio_free(LED_PIN); return ret; } printk(KERN_INFO "LED device driver initialized\n"); return 0; } // 卸载设备驱动程序 static void __exit led_exit(void) { // 删除字符设备 cdev_del(&led_cdev); // 销毁设备 device_destroy(dev_class, dev_num); // 销毁设备类别 class_destroy(dev_class); // 释放设备号 unregister_chrdev_region(dev_num, 1); // 释放GPIO资源 gpio_free(LED_PIN); printk(KERN_INFO "LED device driver unloaded\n"); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("LED device driver"); ``` 在上述代码中,我们使用`gpio_request()`函数来申请GPIO资源,并使用`gpio_direction_output()`函数将GPIO设置为输出模式。在`led_write()`函数中,我们根据用户空间中读取的数据来控制LED的状态。在`led_init()`函数中,我们先申请GPIO资源,然后创建字符设备,并将其注册到内核中。在`led_exit()`函数中,我们释放了GPIO资源,并删除了字符设备
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值