虹口网站建设公司,兴义市 网站建设,想做个外贸网站,产品网站定制自旋锁使用注意事项:自旋锁保护的“临界区”要尽可能的短。
因此#xff0c;在open()函数中申请“spinlock_t自旋锁结构变量”#xff0c;然后在release()函数中释放“spinlock_t自旋锁结构变量”#xff0c;这种方法就行不通了。如果使用一个变量“dev_stats”来表示“共享…自旋锁使用注意事项:自旋锁保护的“临界区”要尽可能的短。
因此在open()函数中申请“spinlock_t自旋锁结构变量”然后在release()函数中释放“spinlock_t自旋锁结构变量”这种方法就行不通了。如果使用一个变量“dev_stats”来表示“共享资源的使用标志”则“dev_stats 0”表示共享资源已经被使用而“dev_stats 0”表示允许使用共享资源。因此真正实现设备互斥访问的是变量“dev_stats”我们用自旋锁对“dev_stats”来做保护就可以实现“互斥访问”共享资源。 1、创建MySpinlockLED目录
输入“cd /home/zgq/linux/Linux_Drivers/回车”
切换到“/home/zgq/linux/Linux_Drivers/”目录
输入“mkdir MySpinlockLED回车”创建“MySpinlockLED”目录
输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/”目录下的文件和文件夹 2、添加gpio_led节点
若在stm32mp157d-atk.dts文件中的根节点下没有gpio_led节点则添加gpio_led节点 3、编译设备树
1)、在VSCode终端输入“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/”目录下的所有文件和文件夹 4、创建LED.c
#include LED.h
#include linux/gpio.h
//使能gpio_request(),gpio_free(),gpio_direction_input(),
//使能gpio_direction_output(),gpio_get_value(),gpio_set_value()
#include linux/of_gpio.h
//使能of_gpio_named_count(),of_gpio_count(),of_get_named_gpio() struct MySpinlockLED_dev strMySpinlockLED; int Get_gpio_num(void);
int led_GPIO_request(void);
void led_switch(u8 sta,struct MySpinlockLED_dev *dev); int Get_gpio_num(void)
{ int ret 0; const char *str; /* 设置LED所使用的GPIO */ /* 1、获取设备节点strMySpinlockLED */ strMySpinlockLED.nd of_find_node_by_path(/gpio_led); //path/gpio_led使用“全路径的节点名“在“stm32mp157d-atk.dts“中查找节点“gpio_led” //返回值:返回找到的节点如果为NULL表示查找失败。 if(strMySpinlockLED.nd NULL) { printk(gpio_led node not find!\r\n); return -EINVAL; } /* 2.读取status属性 */ ret of_property_read_string(strMySpinlockLED.nd, status, str); //在gpio_led节点中status okay; //指定的设备节点strMySpinlockLED.nd //pronamestatus给定要读取的属性名字 //out_stringstr:返回读取到的属性值 //返回值:0读取成功负值读取失败。 if(ret 0) return -EINVAL; if (strcmp(str, okay)) return -EINVAL; //strcmp(s1,s2),当s1s2时返回值为负数 //strcmp(s1,s2),当s12时返回值为正数 //strcmp(s1,s2),当s1s2时返回值为0 /* 3、获取compatible属性值并进行匹配 */ ret of_property_read_string(strMySpinlockLED.nd, compatible, str); //在gpio_led节点中compatible zgq,led; //指定的设备节点strMySpinlockLED.nd //pronamecompatible给定要读取的属性名字 //out_stringstr:返回读取到的属性值 //返回值:0读取成功负值读取失败。 if(ret 0) { printk(gpio_led node: Failed to get compatible property\n); return -EINVAL; } if (strcmp(str, zgq,led)) { printk(gpio_led node: Compatible match failed\n); return -EINVAL; } /* 4、 根据设备树中的led-gpio属性得到LED所使用的LED编号 */ strMySpinlockLED.led_gpio of_get_named_gpio(strMySpinlockLED.nd, led-gpio, 0); //在gpio_led节点中led-gpio gpioi 0 GPIO_ACTIVE_LOW //npstrMySpinlockLED.nd,指定的“设备节点” //propnameled-gpio给定要读取的属性名字 //Index0,给定的GPIO索引为0 //返回值正值获取到的GPIO编号负值失败。 if(strMySpinlockLED.led_gpio 0) { printk(cant get led-gpio); return -EINVAL; } printk(led-gpio num %d\r\n, strMySpinlockLED.led_gpio); //打印结果为“led-gpio num 128“ //因为GPIO编号是从0开始的GPIOI端口的序号是8每个端口有16个IO口因此GPIOI0的编号为8*16128 return 0;
} int led_GPIO_request(void)
{ int ret 0; /* 5.向gpio子系统申请使用“gpio编号” */ ret gpio_request(strMySpinlockLED.led_gpio, LED-GPIO); //gpiostrMySpinlockLED.led_gpio指定要申请的“gpio编号” //IabelLED-GPIO给这个gpio引脚设置个名字为LED-GPIO //返回值0申请“gpio编号”成功;其他值申请“gpio编号”失败 if (ret) { printk(KERN_ERR strMySpinlockLED: Failed to request led-gpio\n); return ret; } /* 6、设置PI0为输出并且输出高电平默认关闭LED灯 */ ret gpio_direction_output(strMySpinlockLED.led_gpio, 1); //gpiostrMySpinlockLED.led_gpio,指定的“gpio编号”这里是128对应的是GI0引脚 //value1设置引脚输出高电平 //返回值0设置“引脚输出为vakued的值”成功;负值设置“引脚输出为vakued的值”失败。 if(ret 0) { printk(cant set gpio!\r\n); } return 0;
} void led_switch(u8 sta,struct MySpinlockLED_dev *dev)
{
if(sta LEDON) { gpio_set_value(dev-led_gpio, 0); /* 打开LED灯 */
}
else if(sta LEDOFF) { gpio_set_value(dev-led_gpio, 1); /* 关闭LED灯 */
}
} 5、创建LED.h
#ifndef __LED_H
#define __LED_H #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/cdev.h //使能cdev结构
#include linux/cdev.h //使能class结构和device结构
#include linux/of.h //使能device_node结构
#include linux/spinlock_types.h //使能spinlock_t结构 #define LEDOFF 0 /* 关灯 */
#define LEDON 1 /* 开灯 */ struct MySpinlockLED_dev{ dev_t devid; /*声明32位变量devid用来给保存设备号*/ int major; /*主设备号*/ int minor; /*次设备号*/ struct cdev cdev; /*字符设备结构变量cdev */ struct class *class; /*类*/ struct device *device; /*设备*/ struct device_node *nd; /*设备节点*/ int led_gpio; /*led所使用的GPIO编号*/ int dev_stats; /*使用状态0设备未使用;0,设备已经被使用 */ spinlock_t lock; /* 自旋锁 */
};
extern struct MySpinlockLED_dev strMySpinlockLED; extern int Get_gpio_num(void);
extern int led_GPIO_request(void);
extern void led_switch(u8 sta,struct MySpinlockLED_dev *dev); #endif 6、创建LEDInterface.c
#include LED.h
#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
//使能MySpinlockLED_init(),MySpinlockLED_exit()
#include linux/gpio.h
//使能gpio_request(),gpio_free(),gpio_direction_input(),
//gpio_direction_output(),gpio_get_value(),gpio_set_value()
#include linux/spinlock.h
//使能DEFINE_SPINLOCK()spin_lock_init(),spin_lock(),spin_trylock(),spin_is_locked()
//spin_lock_irq(),spin_unlock_irq(),spin_lock_irqsave(),spin_unlock_irqrestore() #define MySpinlockLED_CNT 1 //定义设备数量为1
#define MySpinlockLED_NAME MySpinlockLEDName //定义设备的名字 /* 打开设备 */
static int MySpinlockLED_open(struct inode *inode, struct file *filp)
{ unsigned long flags; filp-private_data strMySpinlockLED; /*设置私有数据*/ spin_lock_irqsave(strMySpinlockLED.lock, flags);
/* 上锁准备修改strMySpinlockLED.dev_stats */ if (strMySpinlockLED.dev_stats) { /*strMySpinlockLED.dev_stats0表示“共享资源“被使用了*/
spin_unlock_irqrestore(strMySpinlockLED.lock, flags);
/* 共享资源被使用了记住要解锁 */ return -EBUSY; } strMySpinlockLED.dev_stats;
/*strMySpinlockLED.dev_stats加1记录“共享资源“设备被使用了*/ spin_unlock_irqrestore(strMySpinlockLED.lock, flags);
/* 修改strMySpinlockLED.dev_stats后要记住解锁 */ printk(MySpinlockLED_open!\r\n); return 0;
} /* 从设备读取数据保存到首地址为buf的数据块中长度为cnt个字节 */
//file结构指针变量flip表示要打开的设备文件
//buf表示用户数据块的首地址
//cnt表示用户数据的长度单位为字节
//loff_t结构指针变量offt表示“相对于文件首地址的偏移”
static ssize_t MySpinlockLED_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{ return 0;
} /* 向设备写数据将数据块首地址为buf的数据长度为cnt个字节发送给用户 */
//file结构指针变量flip表示要打开的设备文件
//buf表示用户数据块的首地址
//cnt表示用户数据的长度单位为字节
//loff_t结构指针变量offt表示“相对于文件首地址的偏移”
static ssize_t MySpinlockLED_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{ int ret 0; unsigned char databuf[1]; unsigned char ledstat; ret copy_from_user(databuf, buf, cnt);
//将buf[]中的前cnt个字节拷贝到databuf[]中 if(ret 0){ printk(kernel write failed!\r\n); ret -EFAULT; } ledstat databuf[0];/*获取到应用传递进来的开关灯状态*/ led_switch(ledstat,filp-private_data);/*执行开灯或执行关灯*/ return ret;
} /* 关闭/释放设备 */
static int MySpinlockLED_release(struct inode *inode, struct file *filp)
{ unsigned long flags; struct MySpinlockLED_dev *dev filp-private_data; /* 关闭驱动文件的时候将dev_stats减1 */ spin_lock_irqsave(dev-lock, flags);
/* 上锁,准备修改dev-dev_stats */ if (dev-dev_stats) {
dev-dev_stats--;
/*strMySpinlockLED.dev_stats减1记录“共享资源“设备没有被使用*/ } spin_unlock_irqrestore(dev-lock, flags);
/* 修改完dev-dev_stats后记住解锁 */ return 0;
} /*声明file_operations结构变量MyCharDevice_fops*/
/*它是指向设备的操作函数集合变量*/
const struct file_operations MySpinlockLED_fops { .owner THIS_MODULE, .open MySpinlockLED_open, .read MySpinlockLED_read, .write MySpinlockLED_write, .release MySpinlockLED_release,
}; /*驱动入口函数 */
static int __init MySpinlockLED_init(void)
{ int ret; strMySpinlockLED.dev_stats0;
/*初始化“共享资源使用标志”*/ spin_lock_init(strMySpinlockLED.lock); /* 初始化自旋锁 */ retGet_gpio_num();//读引脚编号 if(ret 0) return ret; /* 1、申请“gpio编号”*/ retled_GPIO_request();//申请“gpio编号” if(ret 0) return ret;//向gpio子系统申请使用“gpio编号” 失败 /*2、申请设备号*/ strMySpinlockLED.major0; if(strMySpinlockLED.major)/*如果指定了主设备号*/ { strMySpinlockLED.devid MKDEV(strMySpinlockLED.major, 0); //输入参数strMySpinlockLED.major为“主设备号” //输入参数0为“次设备号”大部分驱动次设备号都选择0 //将strMySpinlockLED.major左移20位再与0相或就得到“Linux设备号”
retregister_chrdev_region( strMySpinlockLED.devid,\ MySpinlockLED_CNT, \ MySpinlockLED_NAME ); //strMySpinlockLED.devid表示起始设备号 //MySpinlockLED_CNT表示次设备号的数量 //MySpinlockLED_NAME表示设备名 if(ret 0) goto free_gpio; } else { /* 没有定义设备号 */
retalloc_chrdev_region( strMySpinlockLED.devid,\ 0, \ MySpinlockLED_CNT,\ MySpinlockLED_NAME); /* 申请设备号 */ //strMySpinlockLED.devid保存申请到的设备号 //0次设备号的起始地址 //MySpinlockLED_CNT要申请的次设备号数量 //MySpinlockLED_NAME表示“设备名字” if(ret 0) goto free_gpio; strMySpinlockLED.major MAJOR(strMySpinlockLED.devid); /* 获取分配号的主设备号 */ //输入参数strMySpinlockLED.devid为“Linux设备号” //将strMySpinlockLED.devid右移20位得到“主设备号” strMySpinlockLED.minor MINOR(strMySpinlockLED.devid); /* 获取分配号的次设备号 */ //输入参数strMySpinlockLED.devid为“Linux设备号” //将strMySpinlockLED.devid与0xFFFFF相与后得到“次设备号” } /*3、注册字符设备*/ strMySpinlockLED.cdev.owner THIS_MODULE; //使用THIS_MODULE将owner指针指向当前这个模块 cdev_init(strMySpinlockLED.cdev,MySpinlockLED_fops); //注册字符设备初始化“字符设备结构变量strMySpinlockLED.cdev” //strMySpinlockLED.cdev是等待初始化的结构体变量 //MySpinlockLED_fops就是字符设备文件操作函数集合 /*4、添加字符设备*/ retcdev_add(strMySpinlockLED.cdev,strMySpinlockLED.devid,MySpinlockLED_CNT); //添加字符设备 /*strMySpinlockLED.cdev表示指向要添加的字符设备即字符设备结构strMySpinlockLED.cdev变量*/ //strMySpinlockLED.devid表示设备号 //MySpinlockLED_CNT表示需要添加的设备数量 if(ret 0 ) //添加字符设备失败 goto del_register; printk(dev id major %d,minor %d\r\n, strMySpinlockLED.major, strMySpinlockLED.minor); printk(MySpinlockLED_init is ok!!!\r\n); /*5、自动创建设备节点 */ strMySpinlockLED.class class_create(THIS_MODULE, MySpinlockLED_NAME); if (IS_ERR(strMySpinlockLED.class)){ goto del_cdev; } /*6、创建设备 */ strMySpinlockLED.device device_create(strMySpinlockLED.class, NULL, strMySpinlockLED.devid, NULL, MySpinlockLED_NAME); //创建设备 //设备要创建在strMySpinlockLED.class类下面 //NULL表示没有父设备 //strMySpinlockLED.devid是设备号; //参数drvdataNULL设备没有使用数据 //MySpinlockLED_NAME是设备名字 //如果设置fmtMySpinlockLED_NAME 的话就会生成/dev/MySpinlockLED_NAME设备文件。 //返回值就是创建好的设备。 if (IS_ERR(strMySpinlockLED.device)){ goto destroy_class; } return 0; destroy_class: class_destroy(strMySpinlockLED.class); //删除类 //strMySpinlockLED.class就是要删除的类 del_cdev: cdev_del(strMySpinlockLED.cdev); //删除字符设备 //strMySpinlockLED.cdev表示指向需要删除的字符设备即字符设备结构strMySpinlockLED.cdev变量 del_register: unregister_chrdev_region(strMySpinlockLED.devid, MySpinlockLED_CNT); /* 释放设备号 */ //strMySpinlockLED.devid需要释放的起始设备号 //MySpinlockLED_CNT需要释放的次设备号数量 free_gpio://申请设备号失败 /*释放gpio编号*/ gpio_free(strMySpinlockLED.led_gpio); return -EIO;
} /*驱动出口函数 */
static void __exit MySpinlockLED_exit(void)
{ /*1、删除字符设备*/ cdev_del(strMySpinlockLED.cdev); /*删除字符设备*/ /*strMySpinlockLED.cdev表示指向需要删除的字符设备即字符设备结构strMySpinlockLED.cdev变量*/ /*2、 释放设备号 */ unregister_chrdev_region(strMySpinlockLED.devid, MySpinlockLED_CNT); /*释放设备号 */ //strMySpinlockLED.devid需要释放的起始设备号 //MySpinlockLED_CNT需要释放的次设备号数; /*3、 删除设备 */ device_destroy(strMySpinlockLED.class, strMySpinlockLED.devid); //删除创建的设备 //strMySpinlockLED.class是要删除的设备所处的类 //strMySpinlockLED.devid是要删除的设备号 /*4、删除类*/ class_destroy(strMySpinlockLED.class); //删除类 //strMySpinlockLED.class就是要删除的类 /*5、释放gpio编号*/ gpio_free(strMySpinlockLED.led_gpio);
} module_init(MySpinlockLED_init);
//指定MySpinlockLED_init()为驱动入口函数
module_exit(MySpinlockLED_exit);
//指定MySpinlockLED_exit()为驱动出口函数 MODULE_AUTHOR(Zhanggong);//添加作者名字
MODULE_LICENSE(GPL);//LICENSE采用“GPL协议”
MODULE_INFO(intree,Y);
//去除显示“loading out-of-tree module taints kernel.” 7、LED_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运行命令:./LED_APP filename 1|0如果是1表示打开LED如果是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]; unsigned char cnt 0; if(argc ! 3) { printf(Error Usage!\r\n); return -1; } //argv[]是指向输入参数“./LED_App” “/dev/LED” “1” filename argv[1]; //argv[1]指向字符串“/dev/LED” fd open(filename, O_RDWR); //如果打开“/dev/LED”文件成功则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表示关闭失败
printf(close file %s\r\n, filename); return -1; } /* 模拟占用10S LED */
//添加延时程序导致关闭文件推迟为了是演示互斥访问共享资源的效果 while(1) { sleep(5); cnt; printf(App running times:%d\r\n, cnt); if(cnt 2) break; } /* 关闭设备 */ retvalue close(fd); //fd表示要关闭的“文件描述符” //返回值等于0表示关闭成功 //返回值小于0表示关闭失败 if(retvalue 0) { printf(Cant close file %s\r\n, filename); return -1; }
else printf(close file %s\r\n, filename); return 0;
} 8、创建Makefile
KERNELDIR : /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31
#使用“:”将其后面的字符串赋值给KERNELDIR
CURRENT_PATH : $(shell pwd)
#采用“shell pwd”获取当前打开的路径
#使用“$(变量名)”引用“变量的值”
MyAPP : LED_APP
MySpinlockLED_Module-objs LEDInterface.o LED.o
obj-m : MySpinlockLED_Module.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 9、添加“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/MySplinlockLED, /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
} 10、编译
输入“make clean回车”
输入“make drv回车”
输入“make app回车”
输入“make install回车”
输入“ls /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31/ -l回车”产看是存在“LED_APP和MySpinlockLED_Module.ko” 11、测试
启动开发板从网络下载程序
输入“root”
输入“cd /lib/modules/5.4.31/回车”
切换到“/lib/modules/5.4.31/”目录
注意“lib/modules/5.4.31/”在虚拟机中是位于“/home/zgq/linux/nfs/rootfs/”目录下但在开发板中却是位于根目录中。
输入“ls -l”查看“MySpinlockLED_Module.ko和LED_APP”是否存在
输入“depmod”,驱动在第一次执行时需要运行“depmod”
输入“modprobe MySpinlockLED_Module.ko”加载“MySpinlockLED_Module.ko”模块
输入“lsmod”查看有哪些驱动在工作 输入“ls /dev/MySpinlockLEDName -l回车”发现节点文件“/dev/MySpinlockLEDName”
输入“./LED_APP /dev/MySpinlockLEDName 1回车”执行开灯
注意“ ”表示在后台运行LED_APP这个软件。
等待出现“close file /dev/MySpinlockLEDName”按下“回车键”。
注意如果没有出现“close file /dev/MySpinlockLEDName”就急着输入“./LED_APP /dev/MySpinlockLEDName 0回车”就会提示“Cant open file /dev/MySpinlockLEDName”这就避免线程竞争访问贡献资源。
输入“./LED_APP /dev/MySpinlockLEDName 0回车”执行关灯
输入“rmmod MySpinlockLED_Module.ko”卸载“MySpinlockLED_Module.ko”模块
注意:输入“rmmod MySpinlockLED_Module”也可以卸载“MySpinlockLED_Module.ko”模块
输入“lsmod”查看有哪些驱动在工作。
输入“ls /dev/MySpinlockLEDName -l回车”查询节点文件“/dev/MySpinlockLEDName”是否存在