myled.h
#ifndef __MYLED_H__
#define __MYLED_H__
#define PHY_RCC_GPIO 0x5000a28
#define PHY_GPIOE_MODER 0x50006000
#define PHY_GPIOE_ODR 0x50006014
#endif
myled.c
#include "myled.h"
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define CNAME "myled"
int major;
char kbuf[128] = { 0 };
unsigned int* rcc_gpio;
unsigned int* gpioe_moder;
unsigned int* gpioe_odr;
int myled_open(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
//地址映射
rcc_gpio = ioremap(PHY_RCC_GPIO, 4);
if (rcc_gpio == NULL) {
printk("ioremap rcc error\n");
return -ENOMEM;
}
gpioe_moder = ioremap(PHY_GPIOE_MODER, 4);
if (gpioe_moder == NULL) {
printk("ioremap moder error\n");
return -ENOMEM;
}
gpioe_odr = ioremap(PHY_GPIOE_ODR, 4);
if (gpioe_odr == NULL) {
printk("ioremap odr error\n");
return -ENOMEM;
}
//寄存器的初始化
*rcc_gpio |= (1 << 4); // gpioe时钟使能
*gpioe_moder &= ~(3 << 20); //清零moder 21-20bit
*gpioe_moder |= (1 << 20); //设置gpioe10为输出
*gpioe_odr &= ~(1 << 10); // LED1灭
return 0;
}
ssize_t myled_read(struct file* file,
char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if (ret) {
printk("copy data to user error\n");
return -EIO;
}
return size;
}
ssize_t myled_write(struct file* file,
const char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if (ret) {
printk("copy data form user error\n");
return -EIO;
}
//根据kbuf[0], 1灯亮 ,0 灯灭
kbuf[0] == 1 ? (*gpioe_odr |= (1 << 10)) : (*gpioe_odr &= ~(1 << 10));
return size;
}
int myled_close(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
iounmap(rcc_gpio);
iounmap(gpioe_moder);
iounmap(gpioe_odr);
return 0;
}
const struct file_operations fops = {
.open = myled_open,
.read = myled_read,
.write = myled_write,
.release = myled_close,
};
static int __init myled_init(void)
{
// 1.注册字符设备驱动
major = register_chrdev(0, CNAME, &fops);
if (major < 0) {
printk("register char device driver error\n");
return major;
}
printk("create cdev success major = %d\n", major);
return 0;
}
static void __exit myled_exit(void)
{
// 2.注销字符设备驱动
unregister_chrdev(major, CNAME);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
Makefile
arch ?=arm
modname ?=demo
ifeq ($(arch),arm)
KERNELDIR := /lib/modules/$(shell uname -r)/build/
else
KERNELDIR := /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61
endif
PWD:=$(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
make -C $(KERNELDIR) M=$(PWD) clean
obj-m :=$(modname).o