功能:串口助手中输入0:灯全灭,输入1:LED1亮,输入2:LED2亮,输入3:LED3亮
my_led.h
#ifndef __MY_LED_H__
#define __MY_LED_H__
#define PHY_GPIO_RCC 0x50000A28
#define PHY_GPIOE_MODER 0x50006000
#define PHY_GPIOE_ODR 0x50006014
#define PHY_GPIOF_MODER 0x50007000
#define PHY_GPIOF_ODR 0x50007014
#endif
my_led.c
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "my_led.h"
#define DEVNAME "mydev"
char kbuf[128]={0};
int ret;
int major;
unsigned int* vir_rcc;
unsigned int* vir_emoder;
unsigned int* vir_eodr;
unsigned int* vir_fmoder;
unsigned int* vir_fodr;
int my_open(struct inode *myinode, struct file *myfile)
{
printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
return 0;
}
int my_close(struct inode *myinod, struct file *myfile)
{
printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
return 0;
}
ssize_t my_read(struct file *myfile, char __user * ubuf, size_t size, loff_t * myloff)
{
printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
if(size>sizeof(kbuf))
{
size = sizeof(kbuf);
}
ret = copy_to_user(ubuf,kbuf,size);
if(ret)
{
printk("用户读取数据失败\n");
return -EIO;
}
return size;
}
ssize_t my_write(struct file *myfile, const char __user * ubuf, size_t size, loff_t * myloff)
{
printk("%d\t%s\t%s\n",__LINE__,__func__,__FILE__);
if(size>sizeof(kbuf))
{
size = sizeof(kbuf);
}
ret = copy_from_user(kbuf,ubuf,size);
if(ret)
{
printk("内核读取数据失败\n");
return -EIO;
}
switch(kbuf[0])
{
case '0':
(*vir_eodr) &= ~(1<<10);
(*vir_fodr) &= ~(1<<10);
(*vir_eodr) &= ~(1<<8);
break;
case '1':
(*vir_eodr) |= (1<<10);
break;
case '2':
(*vir_fodr) |= (1<<10);
break;
case '3':
(*vir_eodr) |= (1<<8);
break;
}
return size;
}
struct file_operations fop=
{
.open = my_open,
.release = my_close,
.read = my_read,
.write = my_write,
};
static int __init demo_init(void)
{
printk(KERN_ERR "内核加载\n");
major=register_chrdev(0, DEVNAME,&fop);
printk("%d\n",major);
//进行物理地址的映射
vir_fmoder=ioremap(PHY_GPIOF_MODER,4);
if(vir_fmoder==NULL)
{
printk("vir_fmoder 映射失败\n");
return -ENOMEM;
}
printk("vir_fmoder 映射成功\n");
vir_fodr=ioremap(PHY_GPIOF_ODR,4);
if(vir_fodr==NULL)
{
printk("vir_fodr 映射失败\n");
return -ENOMEM;
}
printk("vir_fodr 映射成功\n");
vir_emoder=ioremap(PHY_GPIOE_MODER,4);
if(vir_emoder==NULL)
{
printk("vir_emoder 映射失败\n");
return -ENOMEM;
}
printk("vir_emoder 映射成功\n");
vir_eodr=ioremap(PHY_GPIOE_ODR,4);
if(vir_eodr==NULL)
{
printk("vir_eodr 映射失败\n");
return -ENOMEM;
}
printk("vir_eodr 映射成功\n");
vir_rcc=ioremap(PHY_GPIO_RCC,4);
if(vir_rcc==NULL)
{
printk("vir_rcc 映射失败\n");
return -ENOMEM;
}
printk("vir_rcc 映射成功\n");
//寄存器的初始化
(*vir_emoder) &= ~(3<<20);
(*vir_emoder) |= (1<<20);
(*vir_eodr) &= ~(1<<10);
(*vir_rcc) |= (1<<4);
(*vir_fmoder) &= ~(3<<20);
(*vir_fmoder) |= (1<<20);
(*vir_fodr) &= ~(1<<10);
(*vir_rcc) |= (1<<5);
(*vir_emoder) &= ~(3<<16);
(*vir_emoder) |= (1<<16);
(*vir_eodr) &= ~(1<<8);
(*vir_rcc) |= (1<<4);
return 0;
}
static void __exit demo_exit(void)
{
printk(KERN_ERR "内核卸载\n");
unregister_chrdev(major, DEVNAME);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
Makefile:
modname ?= my_led
arch ?= arm
ifeq ($(arch),arm)
KERNELDIR := /home/ubuntu/fsmp1a/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
else
KERNELDIR := /lib/modules/5.3.0-28-generic/build
endif
PWD:=$(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
make -C $(KERNELDIR) M=$(PWD) clean
obj-m:=$(modname).o
test.c
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "my_led.h"
#define DEVNAME "mydev"
char kbuf[128]={0};
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char const *argv[])
{
char buf[128]={};
int fd=open("/dev/my_lednod",O_RDWR);
if(fd<0)
{
printf("打开设备文件失败\n");
exit(-1);
}
printf("设备文件打开成功\n");
//在终端输入
while(1)
{
printf("请输入控制命令 0:全灭 1:LED1亮 2:LED2亮 3:LED3亮\n");
fgets(buf,sizeof(buf),stdin);
//吃掉换行符
buf[strlen(buf)-1]='\0';
write(fd,buf,sizeof(buf));
//清空buf
memset(buf,0,sizeof(buf));
read(fd,buf,sizeof(buf));
printf("读取到的数据为%s\n",buf);
}
close(fd);
return 0;
}
测试结果: