驱动day4

头文件:

复制代码
#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
#define PHY_LED2_ADDR    0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR    0X50000A28

// 构建开灯关灯的功能码
#define LED_ON _IOW('l', 1,int)
#define LED_OFF _IOW('l', 0,int)
#endif 

运行代码:

复制代码
#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
#include "head.h"

int main(int argc, char const *argv[])
{
    char buf[128]={0};
    int a,b,fd;
    if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }

    while(1)
    {
        fd=-1;
        //从终端读取
        printf("请输入要实现的功能 ");
        printf("0(关灯) 1(开灯)\n");
        printf("请输入>");
        scanf("%d",&a);
        printf("请选择要控制的灯:1(LED1)2(LED2) 3(LED3)\n");
        printf("请输入>");
        scanf("%d",&b);
        switch(b)
        {
            case 1:
                fd=open("/dev/burger0",O_RDWR);
                if(a == 0)
                {   
                   ioctl(fd,LED_ON,&b);
                    break;
                }
                else
                {
                    ioctl(fd,LED_OFF,&b);
                    break;
                }
            case 2:
                fd=open("/dev/burger1",O_RDWR);
                if(a == 0)
                {   
                   ioctl(fd,LED_ON,&b);
                    break;
                }
                else
                {
                    ioctl(fd,LED_OFF,&b);
                    break;
                }
            case 3:
                fd=open("/dev/burger2",O_RDWR);
                if(a == 0)
                {   
                   ioctl(fd,LED_ON,&b);
                    break;
                }
                else
                {
                    ioctl(fd,LED_OFF,&b);
                    break;
                }
        }
        close(fd);
    }
    close(fd);
    return 0;
}

驱动代码:

复制代码
#include <linux/init.h>
#include <linux/module.h>
#include<linux/fs.h>
#include<linux/io.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include"head.h"

char kbuf[128]={0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;
unsigned int major=0;
unsigned int minor=0;
struct cdev *mychdev;
struct class *cls;
struct device *dev;
dev_t devno;
int mycdev_open(struct inode *inode, struct file *file)
{
    int min=MINOR(inode->i_rdev);//获取打开的的文件的次设备号
    file->private_data= (void *)min;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int min=(int)file->private_data;//获取到文件的次设备号
    switch(min)
    {
        case 0: //控制LED1
            switch(cmd)
            {
                case LED_ON:  //开灯
                    vir_led1->ODR |= 1<<10;
                    break;
                case LED_OFF: //关灯
                    vir_led1->ODR &= (~(1<<10));
                    break;
            }
            break;
        case 1:  //控制LED2
            switch(cmd)
            {
                case LED_ON:  //开灯
                    vir_led2->ODR |= 1<<10;
                    break;
                case LED_OFF: //关灯
                    vir_led2->ODR &= (~(1<<10));
                    break;
            }
            break;
        case 2:  //控制LED3
            switch(cmd)
            {
                case LED_ON:  //开灯
                    vir_led3->ODR |= 1<<8;
                    break;
                case LED_OFF: //关灯
                    vir_led3->ODR &= (~(1<<8));
                    break;
            }
            break;
    }
     printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    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,
    .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=vir_led1;
    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 &= (~(3<<20));
    vir_led1->MODER |= (1<<20);
    vir_led1->ODR &= (~(1<<10));
    //led2
    vir_led2->MODER &= (~(3<<20));
    vir_led2->MODER |= (1<<20);
    vir_led2->ODR &= (~(1<<10));
    //led3
    vir_led3->MODER &= (~(3<<16));
    vir_led1->MODER |= (1<<16);
    vir_led1->ODR &= (~(1<<8));
    printk("寄存器初始化成功\n");

    return 0;
}

static int __init mycdev_init(void)
{
    int ret;
    //1.申请一个对象空间cdev_alloc
    mychdev=cdev_alloc();
    if(mychdev == NULL)
    {
        printk("申请字符设备驱动对象失败\n");
        ret = -EFAULT;
        goto out1;
    }
    printk("申请字符设备驱动对象成功\n");
    //2.初始化对象cdev_init
    cdev_init(mychdev,&fops);
    //3.申请设备号  register_chrdev_region()/alloc_chrdev_region()
    if(major == 0)
    {
        ret = alloc_chrdev_region(&devno,minor,3,"burger");
        if(ret)
        {
            printk("动态申请设备号失败\n");
            goto out2;
        }
        major=MAJOR(devno);
        minor=MINOR(devno);
    }
    else
    {
        ret = register_chrdev_region(MKDEV(major,minor),3,"burger");
        if(ret)
        {
            printk("静态申请设备号失败\n");
            goto out2;
        }
    }
    printk("申请设备号成功\n");
    //4.注册驱动对象  cdev_add
    ret = cdev_add(mychdev,MKDEV(major,minor),3);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");
    //5.向上提交目录  class_create
    cls=class_create(THIS_MODULE,"burger");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        goto out4;
    }
    printk("向上提交目录成功\n");
    //6.向上提交设备节点信息  device_create
    int i;  //向上提交三次设备节点信息
    for(i=0;i<3;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"burger%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交节点失败\n");
            goto out5;
        }
    }
     printk("向上提交节点成功\n");
	return 0;
out5:
    for(--i;i>=0;i--)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    class_destroy(cls);
out4:
    cdev_del(mychdev);
out3:
    unregister_chrdev_region(MKDEV(major,minor),3);
out2:
    kfree(mychdev);
out1:
    return ret;
}
static void __exit mycdev_exit(void)
{
    //取消地址映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);
    //注销字符设备驱动
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    class_destroy(cls);
    cdev_del(mychdev);
    unregister_chrdev_region(MKDEV(major,minor),3);
    kfree(mychdev);


}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
相关推荐
西岸行者6 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意6 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码6 天前
嵌入式学习路线
学习
毛小茛6 天前
计算机系统概论——校验码
学习
babe小鑫7 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms7 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下7 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。7 天前
2026.2.25监控学习
学习
im_AMBER7 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J7 天前
从“Hello World“ 开始 C++
c语言·c++·学习