德国的网站后缀,沈阳自助模板建站,竞赛作品发表网站怎么做,短剧分销平台Linux字符设备驱动#xff0c;新字符设备驱动和设备树下的GPIO驱动#xff0c;都是配置IO引脚所使用的GPIO寄存器#xff0c;驱动开发方式和裸机没啥区别。Limux内核提供了pinctrl和gpio子系统用于GPIO驱动#xff0c;借助它可简化GPIO驱动开发。 对GPIO进行读写操作#…Linux字符设备驱动新字符设备驱动和设备树下的GPIO驱动都是配置IO引脚所使用的GPIO寄存器驱动开发方式和裸机没啥区别。Limux内核提供了pinctrl和gpio子系统用于GPIO驱动借助它可简化GPIO驱动开发。 对GPIO进行读写操作使用pinctrl和gpio子系统来实现但像I2C、SPI、LCD这些复杂外设的驱动就要使用“设备树下的platform驱动”来进行开发。学完设备树下的platform驱动说明你已经掌握linux下最常见的驱动编写方式。 Linux驱动开发不需要严格按照框架开发但遵循框架可以大大简化开发的过程提高代码的可维护性。Linux驱动开发遵循一定的框架和规范主要是为了确保驱动的稳定性和兼容性。Linux驱动框架为开发者提供了一套标准的接口和函数使得驱动的开发更加规范化和模块化。例如字符设备驱动、块设备驱动和网络设备驱动都有各自的规范和标准开发者需要实现特定的函数如open、close、write和read等。
platform设备驱动也叫平台设备驱动。 对于STM32MP1来说若要编写“设备树”下的platform设备驱动需要先修改“pinctrl-stm32.c”这个文件否则在使用pinctrl的时候会提示GPIO引脚无法申请到。 1、使用Vscode打开文件夹见下图 修改“pinctrl-stm32.c”文件
1)、打开虚拟机上“VSCode”点击“文件”点击“打开文件夹”点击“zgq”点击“linux”点击“atk-mp1”点击“linux”点击“my_linux”点击“linux-5.4.31”点击“确定”点击“转到”点击“转到文件”。见下图 2)、输入“pinctrl-stm32.c”得到下图 3)、点击文本框下面的“pinctrl-stm32.c”就可以打开这个文件了。
4)、点击“编辑”点击“查找”在弹出的文本框中输入“pinmux_ops stm32_pmx_ops”就会显示“pinmux_ops stm32_pmx_ops结构”见下图 5)、将“.strict true”修改为“.strict false”见下图的红线框 6)、点击“文件”点击“保存”
7)、在VSCode终端输入“make uImage dtbs LOADADDR0XC2000040 -j8
回车”执行编译“Image”和“dtbs”并指定装载的起始地址为0XC2000040j8表示指定采用8线程执行。“make dtbs”用来指定编译设备树。 2、创建“引脚的pinctl节点”为“led_pins_a”
1)、点击“转到”点击“转到文件”在文本框中输入“stm32mp15-pinctrl.dtsi”见下图 2)、点击“文件结果”前面的“stm32mp15-pinctrl.dtsi”就可以打开这个文件了。见下图 3)、点击“编辑”点击“查找”再弹出的文本框中输入“pinctrl”然后按一下“回车”就会跳至“pinctrl”节点。
见下图 4)、输入内容如下 led_pins_a: gpioled-0 {
pins {
pinmux STM32_PINMUX(I, 0, GPIO); /*设置 PI0复用为GPIO功能*/
drive-push-pull;/*设置PI0为推挽输出*/
bias-pull-up; /*设置PI0为内部上拉*/
utput-high; /*设置PI0默认输出为高电平*/
slew-rate 0;/*设置PI0的速度为0档,也就是最慢*/
};
};
这是led的“pinctrl节点”见下图 pinmux STM32_PINMUX(I, 0, GPIO);表示将PI0复用GPIO
pinmux STM32_PINMUX(F, 14, ANALOG);表示将PF14复用为ADC2_in6
pinmux STM32_PINMUX(F, 13, AF6);
表示将PF13重新映射到DFSDM1_DATIN3引脚
pinmux STM32_PINMUX(H, 2, AF14);表示将PH2重映射到LCD_R0引脚; 3、检查引脚是否被其他设备复用
STM32MP1的一个引脚可以复用为多种功能由于“stm32mp15-pimctrl.dtsi”是ST公司根据自己的开发板编写的因此PI0这个引脚就可能被ST公司用作其他功能。因此我们需要修改这个PI0引脚。
1)、打开虚拟机上“VSCode”点击“文件”点击“打开文件夹”点击“zgq”点击“linux”点击“atk-mp1”点击“linux”点击“my_linux”点击“linux-5.4.31”点击“确定”点击“转到”点击“转到文件”在文本框中输入“stm32mp15-pinctrl.dtsi”。
2)、点击“文件结果”前面的“stm32mp15-pinctrl.dtsi”就可以打开这个文件了。
3)、点击“编辑”点击“查找”再弹出的文本框中输入“STM32_PINMUX(I, 0,”然后按一下“回车”就会跳至“STM32_PINMUX(I, 0,”见下图 4)、将上图中画红框中的语句屏蔽掉确保所使用的设备树中一个引脚只复用为一个功能! 4、检查 GPIO是否被其他设备占用
检查引脚是否被其他设备复用后然后检查 GPIO是否被其他设备占用。因为我们是在ST官方提供的设备树上修改的因此还要检査一下当PI0作为GPIO的时候ST官方是否将这个GPIO分配给其他设备。其实对于PI0这个引脚来说不会的因为ST官方将其复用为了LCD_G5所以也就不存在说将其在作为GPIO分配给其他设备。但是我们在实际开发中要考虑到这一点说不定其他的引脚就会被分配给某个设备做GPIO而我们没有检查导致两个设备共用一个GPIO那么肯定有一个因为申请不到GPIO而导致驱动无法工作。所以当我们将一个引脚用作GPIO的时候一定要检査一下“当前设备树”里面是否有其他设备也使用到了这个GPIO保证设备树中只有一个设备树在使用这个GPIO。 5、在设备树文件中创建“设备节点”为“gpioled”
1)、打开虚拟机上“VSCode”点击“文件”点击“打开文件夹”点击“zgq”点击“linux”点击“atk-mp1”点击“linux”点击“my_linux”点击“linux-5.4.31”点击“确定”点击“转到”点击“转到文件”在文本框中输入“stm32mp157d-atk.dts”。打开这个设备树文件,见下图 2)、输入内容如下
gpioled {
compatible zhang,led;
pinctrl-names default;
status okay;
pinctrl-0 led_pins_a; /*表示gpioled节点的父节点为led_pins_a*/
led-gpio gpioi 0 GPIO_ACTIVE_LOW; /*PI0默认输出低电平这个0表示端口引脚的下标*/
};
注意在编写platfonm驱动的时候of_match_table属性表中要有“zhang,led”。
见下图的红方框 注意在编写platfonm驱动的时候of_match_table属性表中要有“zhang,led”。 6、编译
1)、在VSCode终端输入“cd linux-5.4.31/回车”
输入“make uImage dtbs LOADADDR0XC2000040 -j8回车”执行编译“Image”和“dtbs”并指定装载的起始地址为0XC2000040j8表示指定采用8线程执行。“make dtbs”用来指定编译设备树。
2)、输入“ls arch/arm/boot/uImage -l”
查看是否生成了新的“uImage”文件
3)、输入“ls arch/arm/boot/dts/stm32mp157d-atk.dtb -l”
查看是否生成了新的“stm32mp157d-atk.dtb”文件 拷贝输出的文件
4)、输入“cp arch/arm/boot/uImage /home/zgq/linux/atk-mp1/linux/bootfs/ -f回车”执行文件拷贝准备烧录到EMMC
5)、输入“cp arch/arm/boot/dts/stm32mp157d-atk.dtb /home/zgq/linux/atk-mp1/linux/bootfs/ -f回车”执行文件拷贝准备烧录到EMMC 6)、输入“cp arch/arm/boot/uImage /home/zgq/linux/tftpboot/ -f回车”执行文件拷贝准备从tftp下载
7)、输入“cp arch/arm/boot/dts/stm32mp157d-atk.dtb /home/zgq/linux/tftpboot/ -f回车”执行文件拷贝准备从tftp下载 8)、输入“ls -l /home/zgq/linux/atk-mp1/linux/bootfs/回车”查看“/home/zgq/linux/atk-mp1/linux/bootfs/”目录下的所有文件和文件夹 9)、输入“ls -l /home/zgq/linux/tftpboot/回车”查看“/home/zgq/linux/tftpboot/”目录下的所有文件和文件夹
输入“chmod 777 /home/zgq/linux/tftpboot/stm32mp157d-atk.dtb回车”
给“stm32mp157d-atk.dtb”文件赋予可执行权限
输入“chmod 777 /home/zgq/linux/tftpboot/uImage回车” ,给“uImage”文件赋予可执行权限
输入“ls /home/zgq/linux/tftpboot/回车”查看“/home/zgq/linux/tftpboot/” 8、编写“platform驱动”
“引脚的pinctl节点led_pins_a” 和“设备节点gpioled”创建完成后就表示“设备已经准备好了”接下来就要编写“platform驱动”。 1)、创建Platform_GpioLED目录
输入“cd /home/zgq/linux/Linux_Drivers/回车”
切换到“/home/zgq/linux/Linux_Drivers/”
输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/”
输入“mkdir Platform_GpioLED回车”创建“Platform_GpioLED”目录
输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/” 2)、新建Platform_GpioLED_Driver.c
打开虚拟机上“VSCode”点击“文件”点击“打开文件夹”点击“zgq”点击“linux”点击“Linux_Drivers”点击“Platform_GpioLED”。 3)、点击“确定”。点击“文件”点击“新建文件”点击“文件”点击“另存为”。然后在“名称”右边的文本框中输入“Platform_GpioLED_Driver.c”点击“保存”
Platform_GpioLED_Driver.c文件内容如下
#include linux/types.h
/* 数据类型重命名 使能bool,u8,u16,u32,u64, uint8_t, uint16_t, uint32_t, uint64_t 使能s8,s16,s32,s64,int8_t,int16_t,int32_t,int64_t */
#include linux/ide.h //使能copy_from_user(),copy_to_user()
#include linux/module.h //使能LEDDriver_init(),LEDDriver_exit()
#include linux/gpio.h
//使能gpio_request(),gpio_free(),gpio_direction_input(),
//使能gpio_direction_output(),gpio_get_value(),gpio_set_value()
#include linux/cdev.h //使能cdev结构
#include linux/device.h//使能class结构和device结构
#include linux/of_gpio.h
//使能of_gpio_named_count(),of_gpio_count(),of_get_named_gpio()
#include linux/fs.h //使能fasync_struct结构
#include linux/platform_device.h //使能platform_driver结构 #define LEDDEV_CNT 1 //设备数量
#define LEDDEV_NAME platform_led //定义设备的名字 #define LEDOFF 0
#define LEDON 1 /* leddev设备结构体 */
struct leddev_dev{
dev_t devid; /*设备号*/
struct cdev cdev; /*cdev*/
struct class *class; /*类*/
struct device *device; /*设备*/
struct device_node *node;/*LED设备节点*/
int gpio_led; /*LED灯GPIO标号*/
};
struct leddev_dev leddev; /* led设备 */ //函数功能:staLEDON表示开灯, staLEDOFF表示关灯
void led_switch(u8 sta)
{ if (sta LEDON ) gpio_set_value(leddev.gpio_led,0); //设置输出低电平 else if (sta LEDOFF) gpio_set_value(leddev.gpio_led,1); //设置输出高电平
} static int led_gpio_init(struct device_node *nd)
{
int ret; /* 从设备树中获取GPIO */
leddev.gpio_led of_get_named_gpio(nd, led-gpio, 0); //在gpio_led节点中led-gpio gpioi 0 GPIO_ACTIVE_LOW //nd是指定的“设备节点” //propnameled-gpio给定要读取的属性名字 //Index0,给定的GPIO索引为0 //返回值正值获取到的GPIO编号负值失败。
if(!gpio_is_valid(leddev.gpio_led)) { printk(KERN_ERR leddev: Failed to get led-gpio\n); return -EINVAL; } /* 申请使用GPIO */
ret gpio_request(leddev.gpio_led, LED0); //gpioleddev.gpio_led指定要申请的“gpio编号” //LabelLED0给这个gpio引脚设置个名字为LED0 //返回值0申请“gpio编号”成功;其他值申请“gpio编号”失败
if (ret)
{ printk(KERN_ERR led: Failed to request led-gpio\n); return ret;
} /* 将GPIO设置为输出模式并设置GPIO初始电平状态 */
gpio_direction_output(leddev.gpio_led,1);
//设置LED引脚输出高电平 return 0;
} /* 打开设备 */
static int led_open(struct inode *inode, struct file *filp)
{
return 0;
} static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue;
unsigned char databuf[1];
unsigned char ledstat; retvalue copy_from_user(databuf, buf, cnt); //将buf[]中的前cnt个字节拷贝到databuf[]中
if(retvalue 0) {
printk(kernel write failed!\r\n);
return -EFAULT;
} ledstat databuf[0];
if (ledstat LEDON) { led_switch(LEDON); }
else if (ledstat LEDOFF) { led_switch(LEDOFF); } return 0;
} /* 设备操作函数 */
/*声明file_operations结构变量led_fops*/
/*它是指向设备操作函数的集合的变量*/
static struct file_operations led_fops {
.owner THIS_MODULE,
.open led_open,
.write led_write,
}; //函数功能:
//flatform驱动的probe函数,当驱动与设备匹配以后此函数就会被执行
//参数dev指向platform设备
//返回值为0,表示成功;其他负值,失败
static int led_probe(struct platform_device *pdev)
{
int ret; printk(led driver and device was matched!\r\n); /* 初始化 LED */
ret led_gpio_init(pdev-dev.of_node);
if(ret 0) return ret; /* 1、设置设备号 */
ret alloc_chrdev_region(leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
//注册字符设备驱动
//leddev.devid保存申请到的设备号
//0次设备号的起始地址
//LEDDEV_CNT要申请的设备数量
//LEDDEV_NAME表示“设备名字”
if(ret 0) {
pr_err(%s Couldnt alloc_chrdev_region, ret%d\r\n, LEDDEV_NAME, ret);
goto free_gpio;
} /* 2、初始化cdev */
leddev.cdev.owner THIS_MODULE;
cdev_init(leddev.cdev, led_fops);
//初始化字符设备 //leddev.cdev是等待初始化的结构体变量 //led_fops就是字符设备文件操作函数集合 /* 3、添加一个cdev */
ret cdev_add(leddev.cdev, leddev.devid, LEDDEV_CNT);
//添加字符设备
// leddev.cdev表示指向要添加的字符设备即字符设备结构testcdev变量
//leddev.devid表示设备号
//LEDDEV_CNT表示需要添加的设备数量
if(ret 0) goto del_unregister; /* 4、创建类*/
leddev.class class_create(THIS_MODULE, LEDDEV_NAME); //创建类 //使用THIS_MODULE将owner指针指向当前这个模块 //LEDDEV_NAME是类名字 //返回值是指向结构体class的指针也就是创建的类
if (IS_ERR(leddev.class)) goto del_cdev; /* 5、创建设备*/
leddev.device device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME); //创建设备 //设备要创建在leddev.class类下面 //NULL表示没有父设备 //leddev.devid是设备号; //参数drvdataNULL设备没有使用数据 //LEDDEV_NAME是设备名字 //如果设置fmtLEDDEV_NAME的话就会生成/dev/LEDDEV_NAME设备文件。 //返回值就是创建好的设备。
if (IS_ERR(leddev.device)) goto destroy_class; return 0; destroy_class:
class_destroy(leddev.class); //注销类,删除类 //leddev.class就是要删除的类
del_cdev:
cdev_del(leddev.cdev); //删除字符设备 //leddev.cdev表示指向需要删除的字符设备即字符设备结构leddev.cdev变量
del_unregister:
unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 释放设备号 */ //leddev.devid需要释放的设备号 //LEDDEV_CNT需要释放的次设备号数量
free_gpio:
gpio_free(leddev.gpio_led); /* 注销GPIO,leddev.gpio_led要释放的“gpio编号”*/ return -EIO;
} /*
//用来移除platform驱动
//dev指向platform设备
//返回值为0成功;其他负值,失败 */
static int led_remove(struct platform_device *dev)
{
gpio_set_value(leddev.gpio_led, 1);/*先关闭LED再卸载驱动*/
gpio_free(leddev.gpio_led); /* 注销GPIO,leddev.gpio_led要释放的“gpio编号”*/
cdev_del(leddev.cdev); //删除字符设备 //leddev.cdev表示指向需要删除的字符设备即字符设备结构leddev.cdev变量
unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /*注销设备号释放设备号 */ //leddev.devid需要释放的设备号 //LEDDEV_CNT需要释放的次设备号数量
device_destroy(leddev.class, leddev.devid); /* 注销设备 */ //删除创建的设备 //参数leddev.class是设备所处的类leddev.devid是设备号
class_destroy(leddev.class); //注销类,删除类 //leddev.class就是要删除的类 return 0;
} /* 匹配列表 */
//驱动中的compatible属性要和和设备树中的compatible属性相匹配。
static const struct of_device_id led_of_match[] {
{ .compatible zhang,led /*这是驱动中的compatible属性*/},
{/*这是一个空元素,在编写of_device_id时最后一个元素一定要为空*/ }
};
MODULE_DEVICE_TABLE(of, led_of_match);
//声明led_of_match为设备匹配表 /* platform驱动结构体 */
static struct platform_driver led_driver {
.driver {
.name stm32mp1-led, /* 驱动名字stm32mp1-led.ko用于和设备匹配 */
.of_match_table led_of_match, /*of_match_table匹配列表为led_of_match*/
},
.probe led_probe, /*调用led_probe()函数*/
.remove led_remove,/*调用led_remove()函数*/
}; /*驱动的入口函数*/
static int __init leddriver_init(void)
{
return platform_driver_register(led_driver); //向Linux内核注册一个platform驱动 //led_driver:要注册的 platform 驱动 //返回值:负数失败0成功
} /*驱动的出口函数 */
static void __exit leddriver_exit(void)
{
platform_driver_unregister(led_driver); //卸载一个platform驱动 //led_driver要卸载的platform驱动
} module_init(leddriver_init);
//声明leddriver_init()为驱动入口函数,注意module_init为小写字母;
module_exit(leddriver_exit);
//声明leddriver_exit()为驱动出口函数,注意module_init为小写字母;
MODULE_LICENSE(GPL); //LICENSE采用“GPL协议”
MODULE_AUTHOR(zgq); //添加作者名字
MODULE_DESCRIPTION(This is Platform_Driver_Test_Module!);//模块介绍
MODULE_INFO(intree, Y);
//去除显示“loading out-of-tree module taints kernel.” 9、新建PLATFORM_GPIOLED_APP.c
PLATFORM_GPIOLED_APP.c文件内容如下
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdlib.h
#include string.h //APP运行命令:./PLATFORM_GPIOLED_APP MyPLATFORM_GPIOLED 1表示打开LED
//APP运行命令:./PLATFORM_GPIOLED_APP MyPLATFORM_GPIOLED 0表示关闭LED
#define LEDOFF 0 /* 关灯 */
#define LEDON 1 /* 开灯 */ /*
参数argc: argv[]数组元素个数
参数argv[]:是一个指针数组
返回值: 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{ int fd, retvalue; char *filename; unsigned char databuf[1]; if(argc ! 3) { printf(Error Usage!\r\n); return -1; } //argv[]是指向输入参数“./PLATFORM_GPIOLED_App” “/dev/MyPLATFORM_GPIOLED” “1” filename argv[1]; //argv[1]指向字符串“/dev/MyPLATFORM_GPIOLED” fd open(filename, O_RDWR); //如果打开“/dev/PLATFORM_GPIOLED”文件成功则fd为“文件描述符” //fd0表示标准输入流 fd1表示标准输出流fd2表示错误输出流 if(fd 0) { printf(Cant open file %s\r\n, filename); return -1; } databuf[0] atoi(argv[2]); /* 写入的数据是数字的表示打开或关闭 */ retvalue write(fd, databuf, 1); //将databuf[]中前1个字节发送给用户 //返回值大于0表示写入的字节数 //返回值等于0表示没有写入任何数据 //返回值小于0表示写入失败 if(retvalue 0) { printf(write file %s failed!\r\n, filename); close(fd); //fd表示要关闭的“文件描述符” //返回值等于0表示关闭成功 //返回值小于0表示关闭失败 return -1; } /* 关闭设备 */ retvalue close(fd); //fd表示要关闭的“文件描述符” //返回值等于0表示关闭成功 //返回值小于0表示关闭失败 if(retvalue 0) { printf(Cant close file %s\r\n, filename); return -1; } return 0;
} 10、新建Makefile
Makefile文件如下
KERNELDIR : /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31
#使用“:”将其后面的字符串赋值给KERNELDIR CURRENT_PATH : $(shell pwd)
#采用“shell pwd”获取当前打开的路径
#使用“$(变量名)”引用“变量的值” MyAPP : PLATFORM_GPIOLED_APP
MyPLATFORM_GPIOLED-objs Platform_GpioLED_Driver.o
obj-m : MyPLATFORM_GPIOLED.o CC : arm-none-linux-gnueabihf-gcc drv:
$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) modules app:
$(CC) $(MyAPP).c -o $(MyAPP) clean:
$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) clean
rm $(MyAPP) install:
sudo cp *.ko $(MyAPP) /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31/ -f 11、添加“c_cpp_properties.json”
按下“CtrlShiftP”,打开VSCode控制台然后输入“C/C:Edit Configurations(JSON)”,打开以后会自动在“.vscode ”目录下生成一个名为“c_cpp_properties.json” 的文件。
修改c_cpp_properties.json内容如下所示:
{ configurations: [ { name: Linux, includePath: [ ${workspaceFolder}/**, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31, /home/zgq/linux/Linux_Drivers, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/include, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/include, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/include/generated ], defines: [], compilerPath: /usr/bin/gcc, cStandard: gnu11, cppStandard: gnu14, intelliSenseMode: gcc-x64 } ], version: 4
} 12、编译
输入“make clean回车”
输入“make drv回车”
输入“make app回车”
输入“make install回车”
输入“ls /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31/ -l回车”查看是存在“PLATFORM_GPIOLED_APP和MySpinlockLED_Module.ko” 13)、拷贝驱动
输入“cd /home/zgq/linux/Linux_Drivers/Platform_GpioLED/”
输入“ls”
输入“sudo cp MyPLATFORM_GPIOLED.ko /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31”
输入密码“123456回车”
输入“sudo cp PLATFORM_GPIOLED_APP /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31”
输入“cd /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31”
输入“ls -l” 14)、测试
启动开发板从网络下载程序
输入“root”
输入“cd /lib/modules/5.4.31/”
在nfs挂载中切换到“/lib/modules/5.4.31/”目录
注意“lib/modules/5.4.31/”在虚拟机中是位于“/home/zgq/linux/nfs/rootfs/”目录下但在开发板中却是位于根目录中。
输入“ls”
输入“depmod”,驱动在第一次执行时需要运行“depmod”
输入“lsmod”查看有哪些驱动在工作
若MyPLATFORM_GPIOLED.ko在工作则输入“rmmod MyPLATFORM_GPIOLED.ko回车”卸载“MyPLATFORM_GPIOLED.ko”
输入“modprobe MyPLATFORM_GPIOLED.ko”加载“MyPLATFORM_GPIOLED.ko”模块
输入“cd /sys/bus/platform/drivers/”
切换到“/sys/bus/platform/drivers/”目录。
我们在Platform_GpioLED_Driver.c中设置led_driver 中的“.name”字段为“stm32mp1-led”,因此在“/sys/bus/platform/drivers/”目录下存在名为“stmm32mpl-led”这个文件。同理,“/sys/bus/platform/devices/”目录下也存在gpioled的设备文件,也就是设备树中gpioled这个节点。
输入“ls stm32mp1-led -l回车”
输入“cd /sys/bus/platform/devices/”
切换到“/sys/bus/platform/devices/”目录。
输入“ls gpioled -l回车” 输入“cd /lib/modules/5.4.31/”
输入“ls /dev/platform_led -l回车”发现节点文件“/dev/platform_led”
输入“./PLATFORM_GPIOLED_APP /dev/platform_led 1回车”执行写1开灯
输入“./PLATFORM_GPIOLED_APP /dev/platform_led 0回车”执行写0关灯 操作完成则执行卸载模块
输入“rmmod MyPLATFORM_GPIOLED.ko”卸载“MyPLATFORM_GPIOLED.ko”模块
注意:输入“rmmod platform_led”也可以卸载“MyPLATFORM_GPIOLED.ko”模块
输入“lsmod”查看有哪些驱动在工作。
输入“modprobe MyPLATFORM_GPIOLED.ko”加载“MyPLATFORM_GPIOLED.ko”模块
输入“cat /proc/devices回车”查询设备号 platform_led的设备号为241