当前位置: 首页 > news >正文

苏州高端网站建设机构seo推广有哪些

苏州高端网站建设机构,seo推广有哪些,app开发公司名字,网站开发技术文档使用新字符设备驱动的一般模板和“gpio子系统”#xff0c;以及设备树#xff0c;驱动KEY和LED。 1、在stm32mp157d-atk.dts文件中添加“gpio_led”和“key0”节点 打开虚拟机上“VSCode”#xff0c;点击“文件”#xff0c;点击“打开文件夹”#xff0c;点击“zgq”以及设备树驱动KEY和LED。 1、在stm32mp157d-atk.dts文件中添加“gpio_led”和“key0”节点 打开虚拟机上“VSCode”点击“文件”点击“打开文件夹”点击“zgq”点击“linux”点击“atk-mp1”点击“linux”点击“my_linux”点击“linux-5.4.31”点击“确定”点击“stm32mp157d-atk.dts”。 stm32mp157d-atk.dts文件如下 /dts-v1/; #include stm32mp157.dtsi #include stm32mp15xd.dtsi #include stm32mp15-pinctrl.dtsi #include stm32mp15xxaa-pinctrl.dtsi #include stm32mp157-m4-srm.dtsi #include stm32mp157-m4-srm-pinctrl.dtsi #include stm32mp157d-atk.dtsi / { model STMicroelectronics STM32MP157D eval daughter; /*model属性用于描述开发板的名字或设备模块的信息*/ compatible st,stm32mp157d-ed1, st,stm32mp157; /*compatible属性用于将设备和驱动绑定起来*/ chosen {  /*chosen子节点*/ stdout-path serial0:115200n8; }; aliases {    /*aliases子节点*/ serial0 uart4; /*给uart4起个别名叫“serial0”*/ }; reserved-memory { gpu_reserved: gpuf6000000 {  /*gpu节点标签为gpu_reserved*/ reg 0xf6000000 0x8000000; no-map; }; optee_memory: opteefe000000 { reg 0xfe000000 0x02000000; no-map; }; }; stm32mp1_led { compatible atkstm32mp1-led; /*compatible属性用于将设备stm32mp1_led和驱动“.ko”绑定起来*/ status okay; reg 0X50000A28 0X04 /* RCC_MP_AHB4ENSETR */ 0X5000A000 0X04 /* GPIOI_MODER */ 0X5000A004 0X04 /* GPIOI_OTYPER */ 0X5000A008 0X04 /* GPIOI_OSPEEDR */ 0X5000A00C 0X04 /* GPIOI_PUPDR */ 0X5000A018 0X04 ; /* GPIOI_BSRR */ }; }; cpu1{ cpu-supply vddcore; }; gpu { contiguous-area gpu_reserved; status okay; }; optee { status okay; }; 修改后的stm32mp157d-atk.dts文件如下 /dts-v1/; #include stm32mp157.dtsi #include stm32mp15xd.dtsi #include stm32mp15-pinctrl.dtsi #include stm32mp15xxaa-pinctrl.dtsi #include stm32mp157-m4-srm.dtsi #include stm32mp157-m4-srm-pinctrl.dtsi #include stm32mp157d-atk.dtsi / { model STMicroelectronics STM32MP157D eval daughter; /*model属性用于描述开发板的名字或设备模块的信息*/ compatible st,stm32mp157d-ed1, st,stm32mp157; /*compatible属性用于将设备和驱动绑定起来*/ chosen {  /*chosen子节点*/ stdout-path serial0:115200n8; }; aliases {    /*aliases子节点*/ serial0 uart4; /*给uart4起个别名叫“serial0”*/ }; reserved-memory { gpu_reserved: gpuf6000000 {  /*gpu节点标签为gpu_reserved*/ reg 0xf6000000 0x8000000; no-map; }; optee_memory: opteefe000000 { reg 0xfe000000 0x02000000; no-map; }; }; stm32mp1_led { compatible atkstm32mp1-led; /*compatible属性用于将设备stm32mp1_led和驱动“.ko”绑定起来*/ status okay; reg 0X50000A28 0X04 /* RCC_MP_AHB4ENSETR */ 0X5000A000 0X04 /* GPIOI_MODER */ 0X5000A004 0X04 /* GPIOI_OTYPER */ 0X5000A008 0X04 /* GPIOI_OSPEEDR */ 0X5000A00C 0X04 /* GPIOI_PUPDR */ 0X5000A018 0X04 ; /* GPIOI_BSRR */ }; gpio_led { compatible zgq,led; status okay; led-gpio gpioi 0 GPIO_ACTIVE_LOW; }; key0 { compatible zgq,key; status okay; key-gpio gpiog 3 GPIO_ACTIVE_LOW; }; }; cpu1{ cpu-supply vddcore; }; gpu { contiguous-area gpu_reserved; status okay; }; optee { status okay; }; 见下图 2、编译设备树 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/”目录下的所有文件和文件夹 3、查看“gpio_led”节点和“key0”节点 启动开发板从网络下载程序 输入“root” 输入“cd /proc/device-tree/回车” 切换到“/sys/firmware/devicetree/base”目录 输入“ls”查看“gpio_led”节点和“key0”节点设备是否存在 输入“cd gpio_led/回车” 输入“ls”查看“/sys/firmware/devicetree/base/gpio_led”目录下的文件和文件夹 输入“cat compatible回车” 输入“cat led-gpio回车” 输入“cat name回车” 输入“cat status回车” 输入“cd ../回车”返回到“/sys/firmware/devicetree/base”目录 输入“cd key0/回车” 输入“ls”查看“/sys/firmware/devicetree/base/key0”目录下的文件和文件夹 输入“cat compatible回车” 输入“cat key-gpio回车” 输入“cat name回车” 输入“cat status回车” 4、创建Button_LED目录 输入“cd /home/zgq/linux/Linux_Drivers/回车” 切换到“/home/zgq/linux/Linux_Drivers/” 输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/” 输入“mkdir Button_LED回车”创建“Button_LED”目录 输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/” 5、添加“Button.c” #include Button.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() #include linux/delay.h //Linux内核中用到的延时函数 //使能ndelay()udelay()mdelay() struct Button_dev strButton; int Get_gpio_Button_num(void); int Button_gpio_request(void); void Button_free(void); int Read_Button(void); int Get_gpio_Button_num(void) { int ret 0; const char *str; /* 设置Button所使用的GPIO */ /* 1、获取设备节点strButton */ strButton.nd of_find_node_by_path(/key0); //path/key0使用“全路径的节点名“在“stm32mp157d-atk.dts“中查找节点“key0” //返回值:返回找到的节点如果为NULL表示查找失败。 if(strButton.nd NULL) { printk(key0 device node not find!\r\n); return -EINVAL; } /* 2.读取status属性 */ ret of_property_read_string(strButton.nd, status, str); //在key0节点中status okay; //指定的设备节点strButton.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(strButton.nd, compatible, str); //在key0节点中compatible zgq,key; //指定的设备节点strButton.nd //pronamecompatible给定要读取的属性名字 //out_stringstr:返回读取到的属性值 //返回值:0读取成功负值读取失败。 if(ret 0) { printk(key0 node: Failed to get compatible property\n); return -EINVAL; } if (strcmp(str, zgq,key)) { printk(key0 node: Compatible match failed\n); return -EINVAL; } /* 4、 根据设备树中的key-gpio属性得到key0所使用的key0编号 */ strButton.button_gpio_number of_get_named_gpio(strButton.nd, key-gpio, 0); //在key0节点中key-gpio gpiog 3 GPIO_ACTIVE_LOW //npstrButton.nd,指定的“设备节点” //propnamekey-gpio给定要读取的属性名字 //Index0,给定的GPIO索引为0 //返回值正值获取到的GPIO编号负值失败。 if(strButton.button_gpio_number 0) { printk(cant get key-gpio); return -EINVAL; } printk(key-gpio num %d\r\n, strButton.button_gpio_number); //打印结果为“key-gpio num 99“ //因为GPIO编号是从0开始的GPIOG端口的序号是6每个端口有16个IO口因此GPIOI0的编号为6*16 3 99 return 0; } int Button_gpio_request(void) { int ret 0; /* 5.向gpio子系统申请使用“gpio编号” */ ret gpio_request(strButton.button_gpio_number, Button0); //gpiostrButton.button_gpio_number指定要申请的“gpio编号” //labelButton给这个gpio引脚设置个名字为Button //返回值0申请“gpio编号”成功;其他值申请“gpio编号”失败 if (ret) { printk(KERN_ERR Button: Failed to request key0\n); return ret; } /* 6、设置PG3为输入模式*/ ret gpio_direction_input(strButton.button_gpio_number); //gpiostrButton.button_gpio_number,指定的“gpio编号” if(ret 0) { printk(cant set gpio!\r\n); } return 0; } //函数功能释放Button的gpio void Button_free(void) { gpio_free(strButton.button_gpio_number); } //读取按键的值 int Read_Button(void) { int value; u8 ch; ch0; if (gpio_get_value(strButton.button_gpio_number) 0) ch1; mdelay(150);//延时150毫秒 if (gpio_get_value(strButton.button_gpio_number) 0) ch(u8)(ch1); if(ch0x02) { /* Button按下 */ valueBUTTON_VALUE; /* 有效的按键值 */ } else { valueINVABUTTON; /* 无效的按键值 */ } return value; } 6、添加“Button.h” #ifndef __BUTTON_H #define __BUTTON_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/of.h   //使能device_node结构 #define BUTTON_VALUE  1 /* 按键值 */ #define INVABUTTON    0 /* 无效的按键值 */ struct Button_dev{ struct device_node *nd; /*设备节点*/ int button_gpio_number;   /*Button所使用的GPIO编号*/ }; extern struct Button_dev strButton; extern int Get_gpio_Button_num(void); extern int Button_gpio_request(void); extern void Button_free(void); extern int Read_Button(void); #endif 7、添加“Button_drv.c” #include Button_drv.h #include Button.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 //使能ButtonDriver_init(),ButtonDriver_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 ButtonDriver_CNT    1   //定义设备数量为1 #define ButtonDriver_NAME  ButtonDriver  //定义设备的名字 struct ButtonDriver_dev strButtonDriver; /* 打开设备 */ static int ButtonDriver_open(struct inode *inode, struct file *filp) { /*通过判断原子变量的值来检查Button有没有被别的应用使用*/ if (!atomic_dec_and_test(strButtonDriver.lock)) { //当strButtonDriver.lock.counter1时atomic_dec_and_test()返回1 //从strButtonDriver.lock.counter减1如果结果为0就返回1否则返回0; atomic_inc(strButtonDriver.lock);/*小于0的话就加1,使其原子变量等于0*/ return -EBUSY; /* Button被使用返回忙*/ } filp-private_data strButtonDriver; /*设置私有数据*/ printk(ButtonDriver_open!\r\n); return 0; } /* 从设备读取数据保存到首地址为buf的数据块中长度为cnt个字节 */ //file结构指针变量flip表示要打开的设备文件 //buf表示用户数据块的首地址 //cnt表示用户数据的长度单位为字节 //loff_t结构指针变量offt表示“相对于文件首地址的偏移” static ssize_t ButtonDriver_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { int ret 0; int value; valueRead_Button();//读取按键的值 ret copy_to_user(buf, value, sizeof(value)); //将value拷贝到buf[]中 return ret; } /* 向设备写数据将数据块首地址为buf的数据长度为cnt个字节发送给用户 */ //file结构指针变量flip表示要打开的设备文件 //buf表示用户数据块的首地址 //cnt表示用户数据的长度单位为字节 //loff_t结构指针变量offt表示“相对于文件首地址的偏移” static ssize_t ButtonDriver_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { return 0; } /* 关闭/释放设备 */ static int ButtonDriver_release(struct inode *inode, struct file *filp) { struct ButtonDriver_dev *dev filp-private_data; atomic_inc(dev-lock); /*关闭驱动文件的时候释放原子变量便于其它线程使用*/ printk(ButtonDriver_release!\r\n); return 0; } /*声明file_operations结构变量MyCharDevice_fops*/ /*它是指向设备的操作函数集合变量*/ const struct file_operations ButtonDriver_fops { .owner THIS_MODULE, .open ButtonDriver_open, .read ButtonDriver_read, .write ButtonDriver_write, .release ButtonDriver_release, }; /*驱动入口函数 */ static int  __init ButtonDriver_init(void) { int ret; strButtonDriver.lock (atomic_t)ATOMIC_INIT(0); /*初始化原子变量*/ atomic_set(strButtonDriver.lock, 1); /*原子变量初始值strButtonDriver.lock.counter1*/ retGet_gpio_Button_num();//读引脚编号 if(ret 0) return ret; /* 1、申请“gpio编号”*/ retButton_gpio_request();//申请“gpio编号” if(ret 0) return ret;//向gpio子系统申请使用“gpio编号” 失败 /*2、申请设备号*/ strButtonDriver.major0; if(strButtonDriver.major)/*如果指定了主设备号*/ { strButtonDriver.devid MKDEV(strButtonDriver.major, 0); //输入参数strButtonDriver.major为“主设备号” //输入参数0为“次设备号”大部分驱动次设备号都选择0 //将strButtonDriver.major左移20位再与0相或就得到“Linux设备号” retregister_chrdev_region( strButtonDriver.devid,\ ButtonDriver_CNT, \ ButtonDriver_NAME ); //strButtonDriver.devid表示起始设备号 //ButtonDriver_CNT表示次设备号的数量 //ButtonDriver_NAME表示设备名 if(ret 0) goto free_gpio; } else { /* 没有定义设备号 */ retalloc_chrdev_region( strButtonDriver.devid,\ 0, \ ButtonDriver_CNT,\ ButtonDriver_NAME); /* 申请设备号 */ //strButtonDriver.devid保存申请到的设备号 //0次设备号的起始地址 //ButtonDriver_CNT要申请的次设备号数量 //ButtonDriver_NAME表示“设备名字” if(ret 0) goto free_gpio; strButtonDriver.major MAJOR(strButtonDriver.devid); /* 获取分配号的主设备号 */ //输入参数strButtonDriver.devid为“Linux设备号” //将strButtonDriver.devid右移20位得到“主设备号” strButtonDriver.minor MINOR(strButtonDriver.devid); /* 获取分配号的次设备号 */ //输入参数strButtonDriver.devid为“Linux设备号” //将strButtonDriver.devid与0xFFFFF相与后得到“次设备号” } /*3、注册字符设备*/ strButtonDriver.cdev.owner THIS_MODULE; //使用THIS_MODULE将owner指针指向当前这个模块 cdev_init(strButtonDriver.cdev,ButtonDriver_fops); //注册字符设备初始化“字符设备结构变量strButtonDriver.cdev” //strButtonDriver.cdev是等待初始化的结构体变量 //ButtonDriver_fops就是字符设备文件操作函数集合 /*4、添加字符设备*/ retcdev_add(strButtonDriver.cdev,strButtonDriver.devid,ButtonDriver_CNT); //添加字符设备 /*strButtonDriver.cdev表示指向要添加的字符设备即字符设备结构strButtonDriver.cdev变量*/ //strButtonDriver.devid表示设备号 //ButtonDriver_CNT表示需要添加的设备数量 if(ret 0 ) //添加字符设备失败 goto del_register; printk(dev id major %d,minor %d\r\n, strButtonDriver.major, strButtonDriver.minor); printk(ButtonDriver_init is ok!!!\r\n); /*5、自动创建设备节点 */ strButtonDriver.class class_create(THIS_MODULE, ButtonDriver_NAME); if (IS_ERR(strButtonDriver.class)){ goto del_cdev; } /*6、创建设备 */ strButtonDriver.device device_create(strButtonDriver.class, NULL, strButtonDriver.devid, NULL, ButtonDriver_NAME); //创建设备 //设备要创建在strButtonDriver.class类下面 //NULL表示没有父设备 //strButtonDriver.devid是设备号; //参数drvdataNULL设备没有使用数据 //ButtonDriver_NAME是设备名字 //如果设置fmtButtonDriver_NAME 的话就会生成/dev/ButtonDriver_NAME设备文件。 //返回值就是创建好的设备。 if (IS_ERR(strButtonDriver.device)){ goto destroy_class; } return 0; destroy_class: class_destroy(strButtonDriver.class); //删除类 //strButtonDriver.class就是要删除的类 del_cdev: cdev_del(strButtonDriver.cdev); //删除字符设备 //strButtonDriver.cdev表示指向需要删除的字符设备即字符设备结构strButtonDriver.cdev变量 del_register: unregister_chrdev_region(strButtonDriver.devid, ButtonDriver_CNT); /* 释放设备号 */ //strButtonDriver.devid需要释放的起始设备号 //ButtonDriver_CNT需要释放的次设备号数量 free_gpio://申请设备号失败 /*释放gpio编号*/ Button_free(); return -EIO; } /*驱动出口函数 */ static void __exit ButtonDriver_exit(void) { /*1、删除字符设备*/ cdev_del(strButtonDriver.cdev); /*删除字符设备*/ /*strButtonDriver.cdev表示指向需要删除的字符设备即字符设备结构strButtonDriver.cdev变量*/ /*2、 释放设备号 */ unregister_chrdev_region(strButtonDriver.devid, ButtonDriver_CNT); /*释放设备号 */ //strButtonDriver.devid需要释放的起始设备号 //ButtonDriver_CNT需要释放的次设备号数; /*3、 删除设备 */ device_destroy(strButtonDriver.class, strButtonDriver.devid); //删除创建的设备 //strButtonDriver.class是要删除的设备所处的类 //strButtonDriver.devid是要删除的设备号 /*4、删除类*/ class_destroy(strButtonDriver.class); //删除类 //strButtonDriver.class就是要删除的类 /*5、释放gpio编号*/ Button_free(); } module_init(ButtonDriver_init); //指定ButtonDriver_init()为驱动入口函数 module_exit(ButtonDriver_exit); //指定ButtonDriver_exit()为驱动出口函数 MODULE_AUTHOR(Zhanggong);//添加作者名字 MODULE_LICENSE(GPL);//LICENSE采用“GPL协议” MODULE_INFO(intree,Y); //去除显示“loading out-of-tree module taints kernel.” 8、添加“Button_drv.h” #ifndef __BUTTON_DRIVER_H #define __BUTTON_DRIVER_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结构 struct ButtonDriver_dev{ dev_t devid; /*声明32位变量devid用来给保存设备号*/ int major;   /*主设备号*/ int minor;   /*次设备号*/ struct cdev  cdev; /*字符设备结构变量cdev */ struct class *class;     /*类*/ struct device *device;  /*设备*/ atomic_t lock;  /*原子变量*/ }; extern struct ButtonDriver_dev strButtonDriver; #endif 9、添加“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 MyLED_dev  strMyLED; int Get_gpio_led_num(void); int led_GPIO_request(void); void MyLED_free(void); void led_switch(u8 sta); int Get_gpio_led_num(void) { int ret 0; const char *str; /* 设置LED所使用的GPIO */ /* 1、获取设备节点strMyLED */ strMyLED.nd of_find_node_by_path(/gpio_led); //path/gpio_led使用“全路径的节点名“在“stm32mp157d-atk.dts“中查找节点“gpio_led” //返回值:返回找到的节点如果为NULL表示查找失败。 if(strMyLED.nd NULL) { printk(gpio_led node not find!\r\n); return -EINVAL; } /* 2.读取status属性 */ ret of_property_read_string(strMyLED.nd, status, str); //在gpio_led节点中status okay; //指定的设备节点strMyLED.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(strMyLED.nd, compatible, str); //在gpio_led节点中compatible zgq,led; //指定的设备节点strMyLED.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编号 */ strMyLED.led_gpio_number of_get_named_gpio(strMyLED.nd, led-gpio, 0); //在gpio_led节点中led-gpio gpioi 0 GPIO_ACTIVE_LOW //npstrMyLED.nd,指定的“设备节点” //propnameled-gpio给定要读取的属性名字 //Index0,给定的GPIO索引为0 //返回值正值获取到的GPIO编号负值失败。 if(strMyLED.led_gpio_number 0) { printk(cant get led-gpio); return -EINVAL; } printk(led-gpio num %d\r\n, strMyLED.led_gpio_number); //打印结果为“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(strMyLED.led_gpio_number, LED-GPIO); //gpiostrMyLED.led_gpio_number指定要申请的“gpio编号” //IabelLED-GPIO给这个gpio引脚设置个名字为LED-GPIO //返回值0申请“gpio编号”成功;其他值申请“gpio编号”失败 if (ret) { printk(KERN_ERR strMyLED: Failed to request led-gpio\n); return ret; } /* 6、设置PI0为输出并且输出高电平默认关闭LED灯 */ ret gpio_direction_output(strMyLED.led_gpio_number, 1); //gpiostrMyLED.led_gpio_number,指定的“gpio编号”这里是128对应的是GI0引脚 //value1设置引脚输出高电平 //返回值0设置“引脚输出为vakued的值”成功;负值设置“引脚输出为vakued的值”失败。 if(ret 0) { printk(cant set gpio!\r\n); } return 0; } //函数功能释放MyLED的gpio void MyLED_free(void) { gpio_free(strMyLED.led_gpio_number); } void led_switch(u8 sta) { if(sta LEDON) { gpio_set_value(strMyLED.led_gpio_number, 0); /* 打开LED灯 */ } else if(sta LEDOFF) { gpio_set_value(strMyLED.led_gpio_number, 1); /* 关闭LED灯 */ } } 10、添加“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/of.h   //使能device_node结构 #define LEDOFF 0 /* 关灯 */ #define LEDON 1 /* 开灯 */ struct MyLED_dev{ struct device_node *nd; /*设备节点*/ int led_gpio_number;   /*led所使用的GPIO编号*/ }; extern struct MyLED_dev strMyLED; extern int Get_gpio_led_num(void); extern int led_GPIO_request(void); extern void MyLED_free(void); extern void led_switch(u8 sta); #endif 11、添加“LED_drv.c” #include LED_drv.h #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 //使能LEDDriver_init(),LEDDriver_exit() #include linux/gpio.h //使能gpio_request(),gpio_free(),gpio_direction_input(), //gpio_direction_output(),gpio_get_value(),gpio_set_value() #define LEDDriver_CNT    1   //定义设备数量为1 #define LEDDriver_NAME  LEDDriver  //定义设备的名字 struct LEDDriver_dev strLEDDriver; /* 打开设备 */ static int LEDDriver_open(struct inode *inode, struct file *filp) { /*通过判断原子变量的值来检查LED有没有被别的应用使用*/ if (!atomic_dec_and_test(strLEDDriver.lock)) { //当strLEDDriver.lock.counter1时atomic_dec_and_test()返回1 //从strLEDDriver.lock.counter减1如果结果为0就返回1否则返回0; atomic_inc(strLEDDriver.lock);/*小于0的话就加1,使其原子变量等于0*/ return -EBUSY; /* LED被使用返回忙*/ } filp-private_data strLEDDriver; /*设置私有数据*/ printk(LEDDriver_open!\r\n); return 0; } /* 从设备读取数据保存到首地址为buf的数据块中长度为cnt个字节 */ //file结构指针变量flip表示要打开的设备文件 //buf表示用户数据块的首地址 //cnt表示用户数据的长度单位为字节 //loff_t结构指针变量offt表示“相对于文件首地址的偏移” static ssize_t LEDDriver_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 LEDDriver_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);/*执行开灯或执行关灯*/ return ret; } /* 关闭/释放设备 */ static int LEDDriver_release(struct inode *inode, struct file *filp) { struct LEDDriver_dev *dev filp-private_data; atomic_inc(dev-lock); /*关闭驱动文件的时候释放原子变量便于其它线程使用*/ printk(LEDDriver_release!\r\n); return 0; } /*声明file_operations结构变量MyCharDevice_fops*/ /*它是指向设备的操作函数集合变量*/ const struct file_operations LEDDriver_fops { .owner THIS_MODULE, .open LEDDriver_open, .read LEDDriver_read, .write LEDDriver_write, .release LEDDriver_release, }; /*驱动入口函数 */ static int  __init LEDDriver_init(void) { int ret; strLEDDriver.lock (atomic_t)ATOMIC_INIT(0); /*初始化原子变量*/ atomic_set(strLEDDriver.lock, 1); /*原子变量初始值strLEDDriver.lock.counter1*/ retGet_gpio_led_num();//读引脚编号 if(ret 0) return ret; /* 1、申请“gpio编号”*/ retled_GPIO_request();//申请“gpio编号” if(ret 0) return ret;//向gpio子系统申请使用“gpio编号” 失败 /*2、申请设备号*/ strLEDDriver.major0; if(strLEDDriver.major)/*如果指定了主设备号*/ { strLEDDriver.devid MKDEV(strLEDDriver.major, 0); //输入参数strLEDDriver.major为“主设备号” //输入参数0为“次设备号”大部分驱动次设备号都选择0 //将strLEDDriver.major左移20位再与0相或就得到“Linux设备号” retregister_chrdev_region( strLEDDriver.devid,\ LEDDriver_CNT, \ LEDDriver_NAME ); //strLEDDriver.devid表示起始设备号 //LEDDriver_CNT表示次设备号的数量 //LEDDriver_NAME表示设备名 if(ret 0) goto free_gpio; } else { /* 没有定义设备号 */ retalloc_chrdev_region( strLEDDriver.devid,\ 0, \ LEDDriver_CNT,\ LEDDriver_NAME); /* 申请设备号 */ //strLEDDriver.devid保存申请到的设备号 //0次设备号的起始地址 //LEDDriver_CNT要申请的次设备号数量 //LEDDriver_NAME表示“设备名字” if(ret 0) goto free_gpio; strLEDDriver.major MAJOR(strLEDDriver.devid); /* 获取分配号的主设备号 */ //输入参数strLEDDriver.devid为“Linux设备号” //将strLEDDriver.devid右移20位得到“主设备号” strLEDDriver.minor MINOR(strLEDDriver.devid); /* 获取分配号的次设备号 */ //输入参数strLEDDriver.devid为“Linux设备号” //将strLEDDriver.devid与0xFFFFF相与后得到“次设备号” } /*3、注册字符设备*/ strLEDDriver.cdev.owner THIS_MODULE; //使用THIS_MODULE将owner指针指向当前这个模块 cdev_init(strLEDDriver.cdev,LEDDriver_fops); //注册字符设备初始化“字符设备结构变量strLEDDriver.cdev” //strLEDDriver.cdev是等待初始化的结构体变量 //LEDDriver_fops就是字符设备文件操作函数集合 /*4、添加字符设备*/ retcdev_add(strLEDDriver.cdev,strLEDDriver.devid,LEDDriver_CNT); //添加字符设备 /*strLEDDriver.cdev表示指向要添加的字符设备即字符设备结构strLEDDriver.cdev变量*/ //strLEDDriver.devid表示设备号 //LEDDriver_CNT表示需要添加的设备数量 if(ret 0 ) //添加字符设备失败 goto del_register; printk(dev id major %d,minor %d\r\n, strLEDDriver.major, strLEDDriver.minor); printk(LEDDriver_init is ok!!!\r\n); /*5、自动创建设备节点 */ strLEDDriver.class class_create(THIS_MODULE, LEDDriver_NAME); if (IS_ERR(strLEDDriver.class)){ goto del_cdev; } /*6、创建设备 */ strLEDDriver.device device_create(strLEDDriver.class, NULL, strLEDDriver.devid, NULL, LEDDriver_NAME); //创建设备 //设备要创建在strLEDDriver.class类下面 //NULL表示没有父设备 //strLEDDriver.devid是设备号; //参数drvdataNULL设备没有使用数据 //LEDDriver_NAME是设备名字 //如果设置fmtLEDDriver_NAME 的话就会生成/dev/LEDDriver_NAME设备文件。 //返回值就是创建好的设备。 if (IS_ERR(strLEDDriver.device)){ goto destroy_class; } return 0; destroy_class: class_destroy(strLEDDriver.class); //删除类 //strLEDDriver.class就是要删除的类 del_cdev: cdev_del(strLEDDriver.cdev); //删除字符设备 //strLEDDriver.cdev表示指向需要删除的字符设备即字符设备结构strLEDDriver.cdev变量 del_register: unregister_chrdev_region(strLEDDriver.devid, LEDDriver_CNT); /* 释放设备号 */ //strLEDDriver.devid需要释放的起始设备号 //LEDDriver_CNT需要释放的次设备号数量 free_gpio://申请设备号失败 /*释放gpio编号*/ MyLED_free(); return -EIO; } /*驱动出口函数 */ static void __exit LEDDriver_exit(void) { /*1、删除字符设备*/ cdev_del(strLEDDriver.cdev); /*删除字符设备*/ /*strLEDDriver.cdev表示指向需要删除的字符设备即字符设备结构strLEDDriver.cdev变量*/ /*2、 释放设备号 */ unregister_chrdev_region(strLEDDriver.devid, LEDDriver_CNT); /*释放设备号 */ //strLEDDriver.devid需要释放的起始设备号 //LEDDriver_CNT需要释放的次设备号数; /*3、 删除设备 */ device_destroy(strLEDDriver.class, strLEDDriver.devid); //删除创建的设备 //strLEDDriver.class是要删除的设备所处的类 //strLEDDriver.devid是要删除的设备号 /*4、删除类*/ class_destroy(strLEDDriver.class); //删除类 //strLEDDriver.class就是要删除的类 /*5、释放gpio编号*/ MyLED_free(); } module_init(LEDDriver_init); //指定LEDDriver_init()为驱动入口函数 module_exit(LEDDriver_exit); //指定LEDDriver_exit()为驱动出口函数 MODULE_AUTHOR(Zhanggong);//添加作者名字 MODULE_LICENSE(GPL);//LICENSE采用“GPL协议” MODULE_INFO(intree,Y); //去除显示“loading out-of-tree module taints kernel.” 12、添加“LED_drv.h” #ifndef __LED_DRIVER_H #define __LED_DRIVER_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结构 //使能class结构和device结构 struct LEDDriver_dev{ dev_t devid; /*声明32位变量devid用来给保存设备号*/ int major;   /*主设备号*/ int minor;   /*次设备号*/ struct cdev  cdev; /*字符设备结构变量cdev */ struct class *class;     /*类*/ struct device *device;  /*设备*/ atomic_t lock;  /*原子变量*/ }; extern struct LEDDriver_dev strLEDDriver; #endif 13、添加ButtonLED_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 #include unistd.h //Linux系统编程下用到的延时函数 //使能usleep(),sleep() //#include delay.h //Linux内核中用到的延时函数 //使能ndelay()udelay()mdelay() #define KEY0VALUE  1 /* 按键值 */ #define INVAKEY    0 /* 无效的按键值 */ #define LEDOFF 0 /* 关灯 */ #define LEDON 1 /* 开灯 */ /* 参数argc: argv[]数组元素个数 参数argv[]:是一个指针数组 返回值: 0 成功;其他 失败 ./ButtonLED_APP /dev/MyButton /dev/MyLED */ int main(int argc, char *argv[]) { int fd_button; int fd_led; int retvalue; int keyvalue; int status; /* 1. 判断参数 */ if(argc ! 3) { printf(Error Usage!\r\n); return -1; } //argv[]是指向输入参数“./ButtonLED_APP /dev/MyButton /dev/MyLED” /* 2. 打开文件 */ fd_button open(argv[1], O_RDWR); //如果打开“/dev/MyButton”文件成功则fd_button为“文件描述符”,argv[1]/dev/MyButton if(fd_button 0) { printf(Cant open file %s\r\n, argv[1]); return -1; } fd_led open(argv[2], O_RDWR); //如果打开“/dev/MyLED”文件成功则fd_led为“文件描述符”,argv[2]“/dev/MyLED” if(fd_led 0) { printf(Cant open file %s\r\n, argv[2]); return -1; } /* 3. 读文件 */ while(1) { read(fd_button, keyvalue, sizeof(keyvalue)); if (keyvalue KEY0VALUE) { //如果按键按下 printf(KEY0 Press, value %#X\r\n, keyvalue);/* 按下 */ status LEDON; write(fd_led, status, 1); } else { //如果按键松开 status LEDOFF; write(fd_led, status, 1); //file结构指针变量fd_led表示要打开的设备文件 //bufstatus表示用户数据块的首地址 //cnt1表示用户数据的长度单位为字节 } } /* 关闭设备 */ retvalue close(fd_button); //fd_button表示要关闭的“文件描述符” //返回值等于0表示关闭成功 //返回值小于0表示关闭失败 if(retvalue 0) { printf(Cant close file %s\r\n, argv[1]); return -1; } retvalue close(fd_led); //fd_led表示要关闭的“文件描述符” //返回值等于0表示关闭成功 //返回值小于0表示关闭失败 if(retvalue 0) { printf(Cant close file %s\r\n, argv[2]); return -1; } return 0; } 12、添加“Makefile” #Linux一个Makefile编译多个内核驱动 KERNELDIR : /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31 #使用“:”将其后面的字符串赋值给KERNELDIR CURRENT_PATH : $(shell pwd) #采用“shell pwd”获取当前打开的路径 #使用“$(变量名)”引用“变量的值” MyAPP : ButtonLED_APP obj-m : MyButton.o MyLED.o MyButton-y : Button_drv.o Button.o MyLED-y : LED_drv.o LED.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 13、创建“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/Button_LED, /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 } 14、编译 输入“make clean回车” 输入“make drv回车” 输入“make app回车” 输入“make install回车” 输入“ls /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31/ -l回车”查看是存在“ButtonLED_APP,MyButton.ko和MyLED.ko” 15、测试 启动开发板从网络下载程序 输入“root” 输入“cd /lib/modules/5.4.31/回车” 切换到“/lib/modules/5.4.31/”目录 注意“lib/modules/5.4.31/”在虚拟机中是位于“/home/zgq/linux/nfs/rootfs/”目录下但在开发板中却是位于根目录中。 输入“ls -l”查看“ButtonLED_APP,MyButton.ko和MyLED.ko”是否存在 输入“depmod”,驱动在第一次执行时需要运行“depmod” 输入“modprobe MyButton.ko”加载“MyButton.ko”模块 输入“modprobe MyLED.ko”加载“MyLED.ko”模块 输入“lsmod”查看有哪些驱动在工作 输入“ls /dev/ButtonDriver -l回车”发现节点文件“/dev/ButtonDriver” 输入“ls /dev/LEDDriver -l回车”发现节点文件“/dev/LEDDriver” 输入“./ButtonLED_APP /dev/ButtonDriver /dev/LEDDriver回车” 按下按钮等待串口输出“KEY0 Press, value 0X1”同时LED会亮。
http://www.zqtcl.cn/news/324964/

相关文章:

  • 自适应网站建设公司什么是网站死链
  • 自己给网站做支付接口wordpress elementor
  • 中国最新军事新闻网站优化推广
  • 有没有做3d衣服模型网站php网站开发目的
  • 东莞网站建设方案咨询wordpress易企秀
  • 漳诈网站建设免费的企业网站建设
  • 广州番禺区有什么好玩的地方优化软件有哪些
  • 面包机做面包网站wordpress获取用户注册时间
  • 福州网站建设个人兼职泰州seo排名扣费
  • 泰安北京网站建设公司个人自我介绍网页
  • 网站建设适应全屏如何自动深圳市哪里最繁华
  • 杭州网站推广公司阿里云wordpress 安装目录
  • 厦门优秀网站建设app项目开发流程
  • 工作设计室网站海外网站代理
  • 室内设计官方网站没网站怎么做cpa
  • 哪个网站做欧洲旅游攻略好wordpress编辑器字体大小
  • aspcms 手机网站wordpress 刷浏览量
  • dw网站首页的导航怎么做网站建设企业建站模板
  • 平台型网站建设网站关键词优化seo
  • 齿轮机械东莞网站建设技术支持热搜词排行榜关键词
  • 河南专业做网站网站推广优化c重庆
  • 温州网站建设钱建设工程公司网站
  • 做笑话网站全国大学生职业生涯规划大赛官网
  • 便宜购 网站建设平台推广引流怎么做
  • 怎么用记事本做钓鱼网站制作公司网页的步骤
  • 机械设备东莞网站建设智慧软文网站
  • 个人网站需不需要搭建服务器蘑菇短视频2023版特色功能
  • 网站建设公司是什么东兰县建设局网站
  • 网站优化排名方案软件发布网
  • 企业网站开发价钱低企业策划案例