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

结果

实现效果如上

相关推荐
wdxylb4 小时前
云原生俱乐部-shell知识点归纳(1)
linux·云原生
飞雪20075 小时前
Alibaba Cloud Linux 3 在 Apple M 芯片 Mac 的 VMware Fusion 上部署的完整密码重置教程(二)
linux·macos·阿里云·vmware·虚拟机·aliyun·alibaba cloud
路溪非溪5 小时前
关于Linux内核中头文件问题相关总结
linux
Lovyk8 小时前
Linux 正则表达式
linux·运维
Fireworkitte9 小时前
Ubuntu、CentOS、AlmaLinux 9.5的 rc.local实现 开机启动
linux·ubuntu·centos
sword devil9009 小时前
ubuntu常见问题汇总
linux·ubuntu
ac.char9 小时前
在CentOS系统中查询已删除但仍占用磁盘空间的文件
linux·运维·centos
淮北也生橘1211 小时前
Linux的ALSA音频框架学习笔记
linux·笔记·学习
华强笔记14 小时前
Linux内存管理系统性总结
linux·运维·网络
十五年专注C++开发14 小时前
CMake进阶: CMake Modules---简化CMake配置的利器
linux·c++·windows·cmake·自动化构建