实现LED1/LED2/LED3三盏灯进行点亮,上传CSDN

c逻辑文件

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc,const char * argv[])
{
    char buf[128] = {0};
    int fd = -1;
    fd = open("/dev/myled",O_RDWR);
    if(fd == -1)
    {
        perror("open is error\n");
        return -1;
    }

    while(1)
    {
        buf[0] = !buf[0];
        write(fd,buf,1);
        sleep(1);
    }


    close(fd);
    return 0;
}

驱动文件

#include 
#include 
#include 
#include 
#include 
#include "myled.h"

#define CNAME "myled"
int major;
char kbuf[128] = {0};
unsigned int* virt_rcc;
unsigned int* virt_moder;
unsigned int* virt_odr;
unsigned int* virt_moder2;
unsigned int* virt_odr2;

int myled_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t myled_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
    int ret;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    //1.校验传输数据的大小,如果用户空间写的数据比内核空间数据大小大,需要更正大小
    if(size > sizeof(kbuf)) size = sizeof(kbuf);
    //2.将数据从用户空间拷贝到内核空间
    ret = copy_to_user(ubuf,kbuf,size);
    if(ret) //3.判断是否错误
    {
        printk("copy to user is error\n");
        return -EIO;
    }
    return size; //5.返回拷贝数据大小
}
ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    int ret;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    //1.校验传输数据的大小,如果用户空间写的数据比内核空间数据大小大,需要更正大小
    if(size > sizeof(kbuf)) size = sizeof(kbuf);
    //2.将数据从用户空间拷贝到内核空间
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret) //3.判断是否错误
    {
        printk("copy from user is error\n");
        return -EIO;
    }
    //4.打印传递数据内容
    printk("copy from user kbuf:%s\n",kbuf);
    if(kbuf[0] == 1)
    {
        *virt_odr |= (0x1 << 10); //LED1点亮
        *virt_odr2 |= (0x1 << 10); //LED1点亮
        *virt_odr |= (0x1 << 8); //LED1点亮
    }
    else
    {
        *virt_odr &= (~(0x1 << 10)); //LED1写灭;
        *virt_odr2 &= (~(0x1 << 10)); //LED2写灭;
        *virt_odr &= (~(0x1 << 8)); //LED3写灭;
    }
    return size; //5.返回拷贝数据大小
}
int myled_close (struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

const struct file_operations fops = {
    .open = myled_open,
    .read = myled_read,
    .write = myled_write,
    .release = myled_close,
};
static int __init mycdev_init(void)
{
    //1.注册字符设备驱动
    major = register_chrdev(0,CNAME,&fops);

    if(major < 0) //2.判断返回值
    {
        printk("register chrdev is error\n");
    }
    //3.打印主设备号
    printk("register chrdev major=%d\n",major);

    //4.将物理地址映射为虚拟地址
    //4.1 将rcc地址映射
    
    virt_rcc = ioremap(PHY_RCC_LED1,4);
    if(virt_rcc == NULL)
    {
        printk("rcc ioremap is error\n");
        return -ENOMEM;
    }
    
    //4.2 将MODER寄存器地址映射
    virt_moder = ioremap(PHY_MODER_LED1,4);
    if(virt_moder == NULL)
    {
        printk("moder ioremap is error\n");
        return -ENOMEM;
    }
    //4.2 将MODER寄存器地址映射
    virt_moder2 = ioremap(PHY_MODER_LED2,4);
    if(virt_moder == NULL)
    {
        printk("moder ioremap is error\n");
        return -ENOMEM;
    }
    //4.3 将ODR寄存器地址映射
    virt_odr = ioremap(PHY_ODR_LED1,4);
    if(virt_odr == NULL)
    {
        printk("odr ioremap is error\n");
        return -ENOMEM;
    }
    //4.3 将ODR寄存器地址映射
    virt_odr2 = ioremap(PHY_ODR_LED2,4);
    if(virt_odr == NULL)
    {
        printk("odr ioremap is error\n");
        return -ENOMEM;
    }
    //5.对led1---->PE10引脚初始化
    *virt_rcc |= (0x1 << 4);//5.1 使能GPIOE组时钟[4]=1
    *virt_moder &= (~(0x3 << 20));//5.2 设置PE10引脚为输出模式 [21:20] = 01
    *virt_moder |= (0x1 << 20);
    *virt_odr &= (~(0x1 << 10)); //5.3 设置PE10引脚输出低电平
    
    *virt_moder2 &= (~(0x3 << 20));//5.2 设置PF10引脚为输出模式 [21:20] = 01
    *virt_moder2 |= (0x1 << 20);
    *virt_odr2 &= (~(0x1 << 10)); //5.3 设置PF10引脚输出低电平
    
    *virt_moder &= (~(0x3 << 16));//5.2 设置PE8引脚为输出模式 [17:16] = 01
    *virt_moder |= (0x1 << 16);
    *virt_odr &= (~(0x1 << 8)); //5.3 设置PE8引脚输出低电平
    return 0;
}

static void __exit mycdev_exit(void)
{
    //2.取消地址映射
    iounmap(virt_rcc);
    iounmap(virt_moder);
    iounmap(virt_odr);
    //1.注销字符设备驱动
    unregister_chrdev(major,CNAME);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

Makefile

#定义一个存放架构变量
ARCH ?= X86
#定义一个存放文件名变量
modname ?= demo

ifeq ($(ARCH),arm)
#定义一个变量,存放linux内核源码目录,生成ARM架构
KERNEDIR:=/home/ubuntu/linux-5.10.61
else
#定义一个变量,存放ubuntu的linux内核源码目录,生成X86架构
KERNEDIR:=/lib/modules/$(shell uname -r)/build
endif
#定义一个变量,开启一个终端,执行pwd命令
PWD:=$(shell pwd)

all:
    @#-C:跳转到内核顶层目录下,读取内核顶层目录下的Makefile文件
    @#在内核源码顶层目录下执行:make M=$(shell pwd) modules
    @#M=$(shell pwd):回到当前目录下,只编译当前目录下的文件
    @#make modules:采用模块化方式进行编译
    make -C $(KERNEDIR) M=$(shell pwd) modules
clean:
    make -C $(KERNEDIR) M=$(shell pwd) clean

#指定模块化方式编译的文件
obj-m:=$(modname).o

你可能感兴趣的:(arm)