Linux驱动开发之点亮三盏小灯

头文件

cs 复制代码
#ifndef __HEAD_H__
#define __HEAD_H__

//LED1和LED3的硬件地址
#define PHY_LED1_MODER 0x50006000
#define PHY_LED1_ODR 0x50006014
#define PHY_LED1_RCC 0x50000A28
//LED2的硬件地址
#define PHY_LED2_MODER 0x50007000
#define PHY_LED2_ODR 0x50007014
#define PHY_LED2_RCC 0x50000A28

#endif

驱动代码

cs 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include "head.h"
int major;
char kbuf[128]={0}; 
//定义指针接收映射成功的虚拟内存首地址
unsigned int *vir_moder1;
unsigned int *vir_odr1;
unsigned int *vir_rcc1;

unsigned int *vir_moder2;
unsigned int *vir_odr2;
unsigned int *vir_rcc2;


//定义一个指针用来接收创建类
struct class *cls;

//定义一个指针用来接收接收创建设备信息
struct device *dev;
// 封装操作方法
int mycdev_open(struct inode * inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char  *ubuf, size_t size, loff_t *lof)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    int ret;
    ret=copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filad\n");
        return ret;
    }
    return 0;
}
ssize_t mycdev_write(struct file *file, const char  *ubuf, size_t size, loff_t *lof)
{
    int ret;
    ret=copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy_from_user filed\n");
        return ret;
    }
    if(kbuf[0]=='1' && kbuf[1] == '1')//LED1开灯
    {
        //开灯逻辑
        (*vir_odr1) |= (0X1<<10);
            }
    else if(kbuf[0]=='1' && kbuf[1] == '0')//LED1关灯
    {
        //关灯逻辑
        (*vir_odr1) &= (~(0X1<<10));
    }
    else if(kbuf[0]=='2' && kbuf[1] == '1')//LED2开灯
    {
        //开灯逻辑
        (*vir_odr2) |= (0X1<<10);
    }
    else if(kbuf[0]=='2' && kbuf[1] == '0')//LED1关灯
    {
        //关灯逻辑
        (*vir_odr2) &= (~(0X1<<10));
    }
    else if(kbuf[0]=='3' && kbuf[1] == '1')//LED#开灯
    {
        //开灯逻辑
        (*vir_odr1) |= (0X1<<8);
    }
    else if(kbuf[0]=='3' && kbuf[1] == '0')//LED3关灯
    {
        //关灯逻辑
        (*vir_odr1) &= (~(0X1<<8));
    }

    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,
    .read=mycdev_read,
    .write=mycdev_write,
    .release=mycdev_close,
};
 
static int __init mycdev_init(void)
{
    int i;

    // 注册字符设备驱动
    major = register_chrdev(0, "mychrdev", &fops);
    if(major<0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功major=%d\n",major);
    //向上提交目录信息
    cls = class_create(THIS_MODULE,"mycdev");
    if(IS_ERR(cls))
    {
        printk("向上提交目录信息失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录信息成功\n");

    //向上提交设备信息
    for(i=0;i<3;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i);
        if(IS_ERR(cls))
        {
            printk("向上提交设备信息信息失败\n");
            return -PTR_ERR(cls);
        }
    }
    printk("向上提交设备信息成功\n");
    
    //完成硬件寄存器物理内存的映射
    vir_moder1=ioremap(PHY_LED1_MODER,4);
    if(vir_moder1==NULL)
    {
        printk("LED1物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
     vir_odr1=ioremap(PHY_LED1_ODR,4);
    if(vir_odr1==NULL)
    {
        printk("LED1物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
     vir_rcc1=ioremap(PHY_LED1_RCC,4);
    if(vir_rcc1==NULL)
    {
        printk("LED1物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
    printk("LED1物理内存映射成功\n");

    //LED2物理内存映射
    vir_moder2=ioremap(PHY_LED2_MODER,4);
    if(vir_moder2==NULL)
    {
        printk("LED2物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
     vir_odr2=ioremap(PHY_LED2_ODR,4);
    if(vir_odr2==NULL)
    {
        printk("LED2物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
     vir_rcc2=ioremap(PHY_LED2_RCC,4);
    if(vir_rcc2==NULL)
    {
        printk("LED2物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
    printk("LED2物理内存映射成功\n");

    //LED3物理内存映射
    vir_moder1=ioremap(PHY_LED1_MODER,4);
    if(vir_moder1==NULL)
    {
        printk("LED3物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
     vir_odr1=ioremap(PHY_LED1_ODR,4);
    if(vir_odr1==NULL)
    {
        printk("LED3物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
     vir_rcc1=ioremap(PHY_LED1_RCC,4);
    if(vir_rcc1==NULL)
    {
        printk("LED3物理内存映射失败%d\n",__LINE__);
        return -EFAULT;
    }
    printk("LED3物理内存映射成功\n");

    //硬件寄存器的初始化

    //LED1硬件初始化
    (*vir_moder1) &= (~(0X3<<20));//设置为输出
    (*vir_moder1) |= (0X1<<20);

    //LED2硬件初始化
    (*vir_moder2) &= (~(0X3<<20));//设置为输出
    (*vir_moder2) |= (0X1<<20);

    //LED3硬件初始化
    (*vir_moder1) &= (~(0X3<<16));//设置为输出
    (*vir_moder1) |= (0X1<<16);
    //rcc使能
    (*vir_rcc1) |= (0X1<<4);
    (*vir_rcc2) |= (0X1<<5);

    //默认关灯
    (*vir_odr1) &= (~(0X1<<10));
    (*vir_odr2) &= (~(0X1<<10));
    (*vir_odr1) &= (~(0X1<<8));
    return 0;
}
static void __exit mycdev_exit(void)
{
    //取消物理内存的映射
    iounmap(vir_moder1);
    iounmap(vir_odr1);
    iounmap(vir_rcc1);

    iounmap(vir_moder2);
    iounmap(vir_odr2);
    iounmap(vir_rcc2);
    //销毁设备信息
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }

    //销毁目录信息
    class_destroy(cls);

    //字符设备驱动的注销
    unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

测试文件

cs 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, const char *argv[])
{
    char buf[128] = {};

    int fd0 = open("/dev/mycdev0", O_RDWR);
    int fd1 = open("/dev/mycdev1", O_RDWR);
    int fd2 = open("/dev/mycdev2", O_RDWR);

    if (fd0 < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    printf("成功打开设备文件\n");
    while (1)
    {
        printf("逻辑关系:例如11表示LED1亮 10表示LED1灭...\n");
        fgets(buf, sizeof(buf), stdin); // 从终端读一个字符串存放在buf
        buf[strlen(buf) - 1] = '\0';

        if(buf[0] == '1')
        {
            write(fd0, buf, sizeof(buf)); // 将从终端得到的字符串传递到驱动
        }
        else if(buf[0] == '2')
        {
            write(fd1, buf, sizeof(buf));
        }
        else if(buf[0] == '3')
        {
            write(fd2, buf, sizeof(buf));
        }
    }
    close(fd0);

    return 0;
}

结果

实现效果如上

相关推荐
爱瑞瑞1 小时前
🐧深入浅出的认识 Linux 指令
linux·shell
ajassi20001 小时前
开源 java android app 开发(十一)调试、发布
android·java·linux·开源
小李飞刀李寻欢1 小时前
使用kubeadm部署Kubernetes(k8s)集群的步骤
linux·服务器·ubuntu·kubernetes·k8s
运维成长记2 小时前
阿里云实践创建实例步骤
linux·运维·服务器·阿里云·云计算
THe CHallEnge of THe BrAve2 小时前
Linux检验库是否安装成功
linux·运维·服务器
算家计算3 小时前
告别复杂文档解析噩梦!MonkeyOCR 本地部署教程:支持公式/表格多元素结构化
linux·人工智能·开源
曹勖之3 小时前
ROS2 工作空间中, CMakeLists.txt, setup.py和 package.xml的作用分别是?
xml·linux·服务器·ros2
企鹅侠客4 小时前
ttyd:安全地通过网络共享您的 Linux 终端
linux·运维·ttyd
饭碗、碗碗香5 小时前
【开发常用命令】:服务器与本地之间的数据传输
linux·运维·服务器·笔记·学习
MonkeyBananas5 小时前
在Ubuntu中使用Apache2部署项目
linux·运维·ubuntu