首先在/home/ubuntu/linux-5.10.61/arch/arm/boot/dts中的stm32mp157a-fsmp1a.dts文件里添加设备树信息
然后用make dtbs 编译设备树文件,然后将编译好的文件拷贝到~/nfs/rootfs中
编写驱动文件mycdev.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
char kbuf[128];
struct device_node *dnode;
int gpiono1,gpiono2,gpiono3;
int mycdev_open(struct inode *inode, struct file *file)
{
return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
unsigned long ret;
//从用户空间读取数据
if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
size=sizeof(kbuf);
ret=copy_from_user(kbuf,ubuf,size);
if(ret)//拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
switch(kbuf[0]){
case '1':
gpio_set_value(gpiono1,1);
break;
case '2':
gpio_set_value(gpiono1,0);
break;
case '3':
gpio_set_value(gpiono2,1);
break;
case '4':
gpio_set_value(gpiono2,0);
break;
case '5':
gpio_set_value(gpiono3,1);
break;
case '6':
gpio_set_value(gpiono3,0);
break;
}
return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
return 0;
}
//定义操作方法结构体变量并赋值
struct file_operations fops={
.open=mycdev_open,
.read=mycdev_read,
.write=mycdev_write,
.release=mycdev_close,
};
int major;
static int __init mycdev_init(void)
{
//注册字符设备驱动
major=register_chrdev(0,"mychrdev",&fops);
if(major<0){
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功%d\n",major);
//解析设备树节点信息,通过名字
dnode = of_find_node_by_name(NULL,"myleds");
if(dnode == NULL){
printk("获取设备树节点失败\n");
return dnode;
}
printk("获取设备树节点成功\n");
//根据设备结点的信息结构体获取gpio编号
gpiono1=of_get_named_gpio(dnode,"led1",0);
if(gpiono1<0){
printk("获取GPIO编号失败\n");
return 0;
}
printk("获取GPIO编号成功%d\n",gpiono1);
gpiono2=of_get_named_gpio(dnode,"led2",0);
if(gpiono1<0){
printk("获取GPIO编号失败\n");
return 0;
}
printk("获取GPIO编号成功%d\n",gpiono2);
gpiono3=of_get_named_gpio(dnode,"led3",0);
if(gpiono1<0){
printk("获取GPIO编号失败\n");
return 0;
}
printk("获取GPIO编号成功%d\n",gpiono3);
//申请GPIO编号
gpio_request(gpiono1,NULL);
gpio_request(gpiono2,NULL);
gpio_request(gpiono3,NULL);
//设置GPIO方向为输出并默认输出低电平
gpio_direction_output(gpiono1,0);
gpio_direction_output(gpiono2,0);
gpio_direction_output(gpiono3,0);
//默认关灯
gpio_set_value(gpiono1,0);
gpio_set_value(gpiono2,0);
gpio_set_value(gpiono3,0);
return 0;
}
static void __exit mycdev_exit(void)
{
//灭灯
gpio_set_value(gpiono1,0);
gpio_set_value(gpiono2,0);
gpio_set_value(gpiono3,0);
//释放GPIO编号
gpio_free(gpiono1);
gpio_free(gpiono2);
gpio_free(gpiono3);
//注销字符设备驱动
unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
编写测试文件demo.c:
#include <stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,const char * argv[])
{
char buf[128]={0};
int fd=open("/dev/mychrdev",O_RDWR);
if(fd<0){
printf("打开设备文件失败\n");
}
while(1){
//从终端读取
printf("请输入操作那个灯\n");
printf("1(LED1亮) 2(LED1灭) \n3(LED2亮) 4(LED2灭) \n5(LED3亮) 6(LED3灭)\n");
printf("请输入>>");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]='\0';
//向设备文件中写
write(fd,buf,sizeof(buf));
}
close(fd);
return 0;
}
将编译好的mycdev.ko,a.out文件拷贝到rootfs目录,在串口工具中进行测试。