编写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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值