Pinctrl子系统_04_Pinctrl子系统主要数据结构

news2024/11/16 11:56:48

引言

本节说明Pinctrl子系统中主要的数据结构,对这些数据结构有所了解,也就是对Pinctrl子系统有所了解了。

前面说过,要使用Pinctrl子系统,就需要去配置设备树。

以内核面向对象的思想,设备树可以分为两部分,一部分(左边)用来描述Controller,另一部分(右边)则是描述使用引脚(使用controller)的device

对于controller的部分,内核会抽象出一个 pinctrl_dev 结构体;对于 device 的部分,内核会抽象出一个 device 结构体,device 结构体中会有 pinctrl 方面的成员。

显然,这个 pinctrl 方面的成员肯定会和左边的 pinctrl_dev 结构体产生联系。

那么,它们之间是什么样的关系呢?

答:在我们了解完Pinctrl子系统的数据结构之后,他们之间的关系也就清晰了。

首先,在了解Pinctrl子系统的数据结构前,先回忆一下Pinctrl子系统的三大作用

  1. 引脚枚举与命名(Enumerating and naming ):这个pinctrl支持哪些引脚,这些引脚叫什么名字;
  2. 引脚复用(Multiplexing ):用作什么功能,比如用作GPIO、I2C或其他功能;
  3. 引脚配置(Configuration):配置具体的引脚属性,比如上拉、下拉、open drain、驱动强度等;

记住这三大作用,就可以比较形象的去理解相关的结构体了。

那么,在Pinctrl子系统中,是怎么去实现这三大作用的呢?

pinctrl_desc和pinctrl_dev

我们刚刚说,controller 的部分,内核会抽象出一个 pinctrl_dev 结构体,但是事实上我们并不需要自己构造出这个 pinctrl_dev 结构体,而是使用内核提供的注册接口(pinctrl_register函数),我们只需要提供一个pinctrl_desc,然后调用这个接口,接口的返回值就是一个指向 pinctrl_dev 结构体的指针

通过 pinctrl_devpinctrl_desc 这两个结构体,就可以描述一个 pincontroller

controller相关结构体说明

imx6ull 为例,来了解pinctrl子系统中,controller 主要的数据结构,看看代码中是如何通过这些数据结构,实现 pinctrl 的三大作用的。

以下是 imx6ull 的pinctrl节点:

在设备启动后,这个节点会被转换成一个平台设备,和对应的平台驱动匹配完成后,就会调用对应的 probe 函数。

probe函数的大致流程

根据 compatible 属性值("fsl,imx6ul-iomuxc"),可以找到对应的驱动文件是 pinctrl-imx6ul.c,对应的 probe 函数是 imx6ul_pinctrl_probe,imx6ul_pinctrl_probe中则会调用 imx_pinctrl_probe函数。

imx_pinctrl_probe 函数中,会定义一个结构体指针 imx_pinctrl_desc,指向一个 pinctrl_desc 结构体。

在之后的代码中,首先申请一段内存,用来保存 pinctrl_desc,然后填充 pinctrl_desc 结构体,最后调用 devm_pinctrl_register,进行注册。

三大作用的具体实现

上面是probe函数中相关操作的大致流程,下面来具体说一下,在 Pinctrl 子系统中,是怎么去实现上面说的三大作用(引脚枚举与命名,引脚复用,引脚配置)的。

实现的关键就在于 pinctrl_desc 结构体,下面依次说明。

引脚的枚举与命名

首先看第一个功能,引脚的枚举与命名。

需要注意一下,引脚的枚举与命名分为两种情况

  1. 单个引脚 的枚举与命名;
  2. 多个引脚 的枚举与命名;
单个引脚

单个引脚的枚举和命名,主要是通过 pinctrl_desc 结构体的 pins 成员和 npins 成员来实现的。

其中,pins 成员是一个结构体指针,指向一个 pinctrl_pin_desc 结构体,主要负责引脚的枚举与命名;而 npins 成员则是一个无符号的整型数据,用来记录引脚的总个数

在 probe 函数中,会对 pins 和 npins 赋值,大致流程如下:

其中,imx6ul_pinctrl_info 变量的类型是 imx_pinctrl_soc_info 结构体,他也有 pins 和 npins 成员:

可以看到,他的 pins 成员指向了一个 imx6ul_pinctrl_pads 变量,这个变量是一个结构体数组,我们稍后再说。

综上,相当于执行了:

imx_pinctrl_desc->pins = imx6ull_snvs_pinctrl_pads;

imx_pinctrl_desc->npins = ARRAY_SIZE(imx6ull_snvs_pinctrl_pads);

下面,看一下 imx6ul_pinctrl_pads 变量,他是一个结构体数组。通过对 IMX_PINCTRL_PIN 宏的分析,可以看到,这里主要定义了两个成员:

  1. number(第几个引脚,引脚的枚举)
  2. name (引脚的名字,引脚的命名)

 

总结一下,单个引脚的枚举与命名,主要的相关结构体是:

  1. pinctrl_pin_desc结构体;

多个引脚

上面说 pins 和 npins,他们是描述单个引脚。而在实际使用中,有时候会需要同时操作多个引脚group),比如i2c中我们要用到一组引脚,要如何同时操作多个引脚呢?

答:这个时候就要用到 pinctrl_ops 结构体了:

可以看到, pinctrl_ops结构体的成员全部都是函数指针,它们的功能如下:

struct pinctrl_ops {
    /* 返回已注册的group数
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     */
	int (*get_groups_count) (struct pinctrl_dev *pctldev);

    /* 返回指定group的名字
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - unsigned selector:group选择器,表示选择哪个group。
     */
	const char *(*get_group_name) (struct pinctrl_dev *pctldev,
				       unsigned selector);

    /* 返回指定group的引脚数组,并在num_pins中返回数组大小。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - unsigned selector:group选择器,表示选择哪个group。
     *  - const unsigned **pins:指向存储引脚数组的指针的指针。
     *  - unsigned *num_pins:指向存储引脚数组大小的变量的指针。
     */
	int (*get_group_pins) (struct pinctrl_dev *pctldev,
			       unsigned selector,
			       const unsigned **pins,
			       unsigned *num_pins);

    /* 可选的debugfs钩子函数,用于在debugfs中为特定引脚提供每个设备的信息。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - struct seq_file *s:序列文件结构体指针,用于在debugfs中显示信息。
     *  - unsigned offset:偏移量,表示特定引脚的偏移量。
     */
	void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
			  unsigned offset);

    /* 解析设备树中的“引脚配置节点”,并为其创建映射表条目。这些通过`map`和`num_maps`输出参数返回。此函数是可选的,对于不支持设备树的引脚控制驱动程序可以省略。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - struct device_node *np_config:设备树中的引脚配置节点。
     *  - struct pinctrl_map **map:指向映射表指针的指针,用于返回映射表条目。
     *  - unsigned *num_maps:指向存储映射表条目数量的变量的指针。
     */
	int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
			       struct device_node *np_config,
			       struct pinctrl_map **map, unsigned *num_maps);

    /* 释放通过`dt_node_to_map`创建的映射表条目。必须释放顶层`map`指针,以及映射表条目本身的任何动态分配成员。此函数是可选的,对于不支持设备树的引脚控制驱动程序可以省略。
     *  - struct pinctrl_dev *pctldev:引脚控制设备结构体指针,表示引脚控制器设备。
     *  - struct pinctrl_map *map:映射表指针,需要释放。
     *  - unsigned num_maps:映射表条目数量。
     */
	void (*dt_free_map) (struct pinctrl_dev *pctldev,
			     struct pinctrl_map *map, unsigned num_maps);
};

这里说明一下,pinctrl_ops结构体成员中,有一个很关键的函数指针 dt_node_to_map,他是用来处理设备树的,我们以后再说,这里先点一下。

所以,对于多个引脚(group),相关的结构体是:

  1. pinctrl_ops 结构体;

引脚复用

类似的,引脚的复用也是由一个结构体来实现:pinmux_ops

pinmux_ops 就是 "Pin Multiplexing Operations"的缩写,表示引脚复用操作。

可以看到,结构体内部主要也是一堆函数指针

其中,引脚的复用主要是通过 set_mux 成员来实现的,他也是一个函数指针:

这里目前只对set_mux成员做说明,后面如果有用到其他函数指针,到时候再补充。

struct pinmux_ops {
	int (*request) (struct pinctrl_dev *pctldev, unsigned offset);

	int (*free) (struct pinctrl_dev *pctldev, unsigned offset);

	int (*get_functions_count) (struct pinctrl_dev *pctldev);

	const char *(*get_function_name) (struct pinctrl_dev *pctldev,
					  unsigned selector);

	int (*get_function_groups) (struct pinctrl_dev *pctldev,
				  unsigned selector,
				  const char * const **groups,
				  unsigned *num_groups);

    /* 启用特定的muxing功能与特定的group。驱动程序无需确定启用此功能是否与该组中pin的其他用途冲突,这种冲突由pinmux子系统处理。
     *  - struct pinctrl_dev *pctldev: 指向pinctrl设备结构的指针,用于表示设置mux的pinctrl设备。
     *  - unsigned func_selector: 无符号整数,表示选择什么功能。
     *  - unsigned group_selector: 无符号整数,表示选择哪个group。
     */
	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector,
			unsigned group_selector);

	int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
				    struct pinctrl_gpio_range *range,
				    unsigned offset);

	void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset);

	int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
				   struct pinctrl_gpio_range *range,
				   unsigned offset,
				   bool input);

	bool strict;
};

引脚配置

我们还可以将一个或一组引脚,设置成不同的配置,比如上拉,下拉,open drain(开漏)等等。

这是怎么操作的呢?

答:同样是通过一个结构体:pinconf_ops

pinconf_ops 就是"Pin Configuration Options"的缩写,表示引脚的配置操作。

可以看到,结构体内部主要还是一堆函数指针。

这里主要说明以下四个函数指针:

  1. pin_config_get:获取某个pin的配置;
  2. pin_config_set:设置某个pin的配置;
  3. pin_config_group_get:获取某个group的配置;
  4. pin_config_group_set:设置某个group的配置;

注册pinctrl_dev

填充完 pinctrl_desc 结构体之后,调用 devm_pinctrl_register pinctrl_register,就可以根据 pinctrl_desc 构造出 pinctrl_dev,并且把 pinctrl_dev 放入链表

devm_pinctrl_register
    pinctrl_register
    	struct pinctrl_dev *pctldev;
		pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);

		pctldev->owner = pctldesc->owner;
		pctldev->desc = pctldesc;
		pctldev->driver_data = driver_data;

		/* check core ops for sanity */
		ret = pinctrl_check_ops(pctldev);

		/* If we're implementing pinmuxing, check the ops for sanity */
		ret = pinmux_check_ops(pctldev);

		/* If we're implementing pinconfig, check the ops for sanity */
		ret = pinconf_check_ops(pctldev);

		/* Register all the pins */
		ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);

		list_add_tail(&pctldev->node, &pinctrldev_list);

总结

综上,对于controller,涉及的结构体主要有5个:

  1. pinctrl_desc:用于描述一个特定的引脚控制器(pinctrl)的配置信息,包括该控制器管理的引脚数量、引脚的功能、引脚的默认状态等。
  2. pinctrl_dev:代表一个具体的引脚控制器设备,它与`pinctrl_desc`结构体相关联,用于在系统中表示和管理一个特定的引脚控制器。
  3. pinctrl_ops :定义了对引脚控制器进行操作的一组函数指针,包括引脚的配置、引脚的状态读取、引脚的状态设置等操作。
  4. pinmux_ops:定义了对引脚复用(pin multiplexing)进行操作的一组函数指针,用于配置引脚的不同功能模式,例如将一个引脚配置为GPIO模式或者特定外设的模式。
  5. pinconf_ops:定义了对引脚配置(pin configuration)进行操作的一组函数指针,用于设置和获取引脚的一些特定属性,例如引脚的电压、上下拉设置等。

device相关结构体说明

上面主要是对左边controller相关的结构体说明,下面来讨论一下右边device相关的结构体。

dev_pin_info 结构体

在设备树中,使用pinctrl时,device节点格式如下:

/* For a client device requiring named states */
device {
    pinctrl-names = "active", "idle";
    pinctrl-0 = <&state_0_node_a>;
    pinctrl-1 = <&state_1_node_a &state_1_node_b>;
};

设备节点要么被转换为 platform_device,要么转换为其他结构体(比如i2c_client),但是里面都会有一个 device 结构体。在 device 结构体中会有一个 pins 成员,这个 pins 成员是一个结构体指针,指向一个 dev_pin_info 结构体。

dev_pin_info 结构体保存的就是这个 device 的 pinctrl 信息

下面是 dev_pin_info 结构体的定义:

可以看到,主要定义了:

  1. 一个指向 pinctrl 结构体的结构体指针p;
  2. 4个指向 pinctrl_state 结构体的结构体指针 default_state,init_state,sleep_state,idle_state。

结合device节点,分析理解一下 dev_pin_info 结构体,以下面的device节点为例:

右边的device节点中,定义了两种状态:

  1. 状态0:default(对应 controller 节点 state_0_node_a) ;
  2. 状态1:sleep(对应 controller 节点 state_1_node_a 和 state_1_node_b)。

那么,就会用这些节点,来构造 dev_pin_info 结构体中的 default_state sleep_state

可以看到,dev_pin_info 结构体中已经定义了 4 个pinctrl_state指针,如果要添加我们自定义的state,要怎么记录呢?

答:dev_pin_info 结构体中有一个 pinctrl 结构体,我们自定义的 state 就存放在这个 pinctrl 结构体中。

假设要添加一个自定义的state,名字叫做“plane”,意为飞行模式,那么节点会变成这样:

pinctrl 结构体中有一个 states 成员,这个成员就会以链表的形式保存所有state,根据状态的序号,依次分别是default,sleep,plane。

并且 dev_pin_info 结构体中原先就有定义的 default_state 和 sleep_state,他们也会指向 states 成员中保存的 default 和 sleep 状态信息。

综上,对应device节点,最重要的结构体当属 pinctrl_state 结构体。

当设备进入某种状态时,就要把引脚配置成对应的 state。

那么,我们如何构造 pinctrl_state 呢?

如何构造pinctrl_state?

以下图为例,device 节点中的 pinctrl-0(default状态) 使用的是 state_0_node_a 节点,那么自然就要根据 state_0_node_a 节点来构造出 default_state。

那么,怎么根据pinctrl节点构造state呢?

答:需要用到 pinctrl_ops 结构体中的 dt_node_to_map 成员了。

dt_node_to_map 就是 "device tree node ==》map",顾名思义,就是将设备树的节点转换成一系列的map结构体(即pinctrl_map结构体)的意思。

通过 dt_node_to_map,将 pinctrl 节点转换为 pinctrl_map,再由 pinctrl_map 转换为 pinctrl_setting,最后,pinctrl_setting 会被存入 pinctrl_state 中的 settings 链表。

 

那么,pinctrl_map pinctrl_setting 中,需要保存哪些信息呢?

答:对于 pinctrl 节点,他主要有两个作用:

  1. pin mux,引脚复用;
  2. pin cfg,引脚配置;

那么,显然,pinctrl_map pinctrl_setting 就需要将这两个信息(引脚的复用信息,引脚的配置信息)保存记录下来。

首先,看一下 pinctrl_map 结构体:

可以看到,pinctrl_map 内部有一个联合体(union)data,这个联合体有两个成员:

  1. pinctrl_map_mux,记录复用信息;
  2. pinctrl_map_configs,记录配置信息;

所以,pinctrl_map 既可以记录引脚的复用信息,也可以记录引脚的配置信息;

刚刚说了,pinctrl_map 还会转换出 pinctrl_setting,来看一下 pinctrl_setting 结构体:

可以看到,他也有一个联合体(union) data,并且这个data也有两个成员:

  1. pinctrl_setting_mux,记录复用信息;
  2. pinctrl_setting_configs,记录配置信息;

所以,与 pinctrl_map 一样,pinctrl_setting 也是既可以记录引脚的复用信息,也可以记录引脚的配置信息。

对比 pinctrl_map pinctrl_setting,可以发现两者高度类似:都可以保存引脚的复用信息,配置信息。

综上,我们知道了, 驱动程序会把 pinctrl子节点 转换成一系列(为什么说一系列?因为一个pinctrl子节点可能包含多个引脚)的 pinctrl_map pinctrl_setting 结构体,在 pinctrl_map pinctrl_setting 结构体中会保存引脚的配置信息,复用信息

并且 pinctrl_setting 结构体还会被存入 pinctrl_state,以后我们选择让这个设备进入某种状态时,就会根据这些setting,来设置那些引脚,选择引脚的功能,配置引脚的上下拉,驱动强度等等。

 

使用pinctr_setting

最后,我们来看一下 pinctrl_state 中的这一系列 setting,是如何被调用的,又是如何去配置引脚的

这主要会涉及 pinmux_ops 结构体中的 set_mux(设置复用)和 pinconf_ops 结构体中的 pin_config_set(设置引脚配置),pin_config_group_set(设置group配置)。

调用的流程如下:

really_probe
	pinctrl_bind_pins
		pinctrl_select_state
			/* Apply all the settings for the new state */
			list_for_each_entry(setting, &state->settings, node) {
				switch (setting->type) {
                /* 引脚复用 */
				case PIN_MAP_TYPE_MUX_GROUP:
					ret = pinmux_enable_setting(setting);
							ret = ops->set_mux(...);
				break;

                /* 引脚配置:单引脚,多引脚 */
				case PIN_MAP_TYPE_CONFIGS_PIN:
				case PIN_MAP_TYPE_CONFIGS_GROUP:
					ret = pinconf_apply_setting(setting);
                        switch (setting->type) {
                    	case PIN_MAP_TYPE_CONFIGS_PIN:
							ret = ops->pin_config_set(...);
                        break;
	                    case PIN_MAP_TYPE_CONFIGS_GROUP:
		                    ret = ops->pin_config_group_set(...);
                        break;
	                    default:
		                    return -EINVAL;
                        }
					break;
				default:
					ret = -EINVAL;
				    break;
			}		

这样,左右两边的结构体(controller和device)就产生了联系,当设备进入某种状态时,就可以将引脚设置为对应的配置。

当我们对上述的结构体都有了初步的了解之后,后面就可以开始进行更深入的分析了。

以上就是本节全部内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1502275.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7. 镜面网格

E . 镜面网格 E.镜面网格 E.镜面网格 每次测试时限&#xff1a; 2 秒 每次测试时限&#xff1a;2 秒 每次测试时限&#xff1a;2秒 每次测试的内存限制&#xff1a; 256 兆字节 每次测试的内存限制&#xff1a;256 兆字节 每次测试的内存限制&#xff1a;256兆字节 题目描述 给…

深度学习与人类的智能交互:迈向自然与高效的人机新纪元

引言 随着科技的飞速发展&#xff0c;深度学习作为人工智能领域的一颗璀璨明珠&#xff0c;正日益展现出其在模拟人类认知和感知过程中的强大能力。本文旨在探讨深度学习如何日益逼近人类智能的边界&#xff0c;并通过模拟人类的感知系统&#xff0c;使机器能更深入地理解和解…

每日OJ题_牛客HJ86 求最大连续bit数(IO型OJ)

目录 牛客HJ86 求最大连续bit数 解法代码 牛客HJ86 求最大连续bit数 求最大连续bit数_牛客题霸_牛客网 解法代码 #include <iostream> using namespace std; int main() {int n 0, cnt 0, ret 0;cin >> n;for (int i 0; i < 32; i){if (n & (1 <…

uniapp富文本编辑-editor-vue2-vue3-wangeditor

前言 除了“微信小程序”&#xff0c;其他小程序想要使用editor组件实现富文本编辑&#xff0c;很难vue3项目 官方组件editor&#xff0c;在初始化时有点麻烦&#xff0c;建议搭配第三方组件wangeditor 写在前面 - editor组件缺少editor-icon.css 内容另存为editor-icon.css…

Springboot+vue的物业管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的物业管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的物业管理系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff…

【Haproxy】Haproxy的配置和应用

HAProxy介绍 HAProxy是法国开发者威利塔罗(Willy Tarreau)在2000年使用C语言开发的一个开源软件&#xff0c;是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器&#xff0c;支持基于cookie的持久性&#xff0c;自动故障切换&#xff0c;支持正则表达式及web状态统计&a…

server win搭建apache网站服务器+php网站+MY SQL数据库调用电子阅览室

一、适用场景&#xff1a; 1、使用开源的免费数据库Mysql&#xff1b; 2、自己建网站的发布&#xff1b; 3、使用php代码建网站&#xff1b; 4、使用windows server作为服务器&#xff1b; 5、使用apache作为网站服务器。 二、win server 中apache网站服务器搭建 &#xff0…

AlexNet 网络结构详解

一、基本了解 什么是过拟合&#xff1f; 解决方法 AlexNet网络结构通过使用dropout方法&#xff0c;使一些神经元失活&#xff0c;变相的减少了网络训练的参数化&#xff0c;从而实现减少过拟合。 二、AlexNet网络结构的详细解释 他是由上下两组GPU进行运算的&#xff0c;所以…

数据结构 - 栈和队列

本篇博客将介绍栈和队列的定义以及实现。 1.栈的定义 栈是一种特殊的线性表&#xff0c;只允许在固定的一端进行插入和删除数据&#xff0c;插入数据的一端叫做栈顶&#xff0c;另一端叫做栈底。栈中的数据遵守后进先出的原则 LIFO (Last In First Out)。 插入数据的操作称为压…

遥感卫星影像数据产品级别概述及卫星影像获取

1986年&#xff0c;美国航空航天局&#xff08;NASA&#xff09;定义了一系列数据处理"级别"&#xff0c;用以区分源于其地球观测系统&#xff08;EOS&#xff09;卫星获取的影像生成的标准数据产品。给定任何数据产品&#xff0c;我们可以根据其级别来判断其在生产过…

机器学习--循环神经网路(RNN)2

在这篇文章中&#xff0c;我们介绍一下其他的RNN。 一.深层RNN 循环神经网络的架构是可以任意设计的&#xff0c;之前提到的 RNN 只有一个隐藏层&#xff0c;但 RNN 也可以是深层的。比如把 xt 丢进去之后&#xff0c;它可以通过一个隐藏层&#xff0c;再通过第二个隐藏层&am…

初识Hive

官网地址为&#xff1a; Design - Apache Hive - Apache Software Foundation 一、架构 先来看下官网给的图&#xff1a; 图上显示了Hive的主要组件及其与Hadoop的交互。Hive的主要组件有&#xff1a; UI&#xff1a; 用户向系统提交查询和其他操作的用户界面。截至2011年&…

JavaSec 基础之 URLDNS 链

文章目录 URLDNS 链分析调用链复现反序列化复现 URLDNS 链分析 URLDNS是ysoserial里面就简单的一条利用链&#xff0c;但URLDNS的利用效果是只能触发一次dns请求&#xff0c;而不能去执行命令。比较适用于漏洞验证这一块&#xff0c;而且URLDNS这条利用链并不依赖于第三方的类…

基于Pytorch搭建分布式训练环境

Pytorch系列 文章目录 Pytorch系列前言一、DDP是什么二、DPP原理terms、nodes 和 ranks等相关术语解读DDP 的局限性为什么要选择 DDP 而不是 DP代码演示1. 在一个单 GPU 的 Node 上进行训练&#xff08;baseline&#xff09;2. 在一个多 GPU 的 Node 上进行训练临门一脚&#x…

加密与安全_使用Java代码操作RSA算法生成的密钥对

文章目录 Pre概述什么是非对称加密算法&#xff1f;如何工作&#xff1f;示例&#xff1a;RSA算法特点和优势ECC&#xff1a;另一种非对称加密算法 Code生成公钥和私钥私钥加密私钥加密私钥解密 ( 行不通 )私钥加密公钥解密公钥加密和公钥解密 &#xff08;行不通&#xff09;保…

使用Python快速提取PPT中的文本内容

直接提取PPT中的文本内容可以方便我们进行进一步处理或分析&#xff0c;也可以直接用于其他文档的编撰。通过使用Python程序&#xff0c;我们可以快速批量提取PPT中的文本内容&#xff0c;从而实现高效的信息收集或对其中的数据进行分析。本文将介绍如何使用Python程序提取Powe…

C语言分析基础排序算法——插入排序

目录 插入排序 直接插入排序 希尔排序 希尔排序基本思路解析 希尔排序优化思路解析 完整希尔排序文件 插入排序 直接插入排序 所谓直接插入排序&#xff0c;即每插入一个数据和之前的数据进行大小比较&#xff0c;如果较大放置在后面&#xff0c;较小放置在前面&#x…

Lwip之TCP服务端示例记录(1对多)

前言 实现多个客户端同时连接初步代码结构已经实现完成(通过轮训的方式) // // Created by shchl on 2024/3/8. // #if 1#include <string.h> #include "lwip/api.h" #include "FreeRTOS.h" #include "task.h" #include "usart.h&…

DataGirp导入.sql文件

连接数据库前的配置 进行连接测试 利用DataGirp打开.sql文件 右击执行文件 Run 默认为空的源需要手动添加数据库位置 最后就是导入运行 最后等待即可 &#xff08;到底啦~&#xff09;

找不到本地组策略编辑器解决办法

创建记事本写入以下命令 echo offpushd "%~dp0"dir /b %systemroot%\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >gp.txtdir /b %systemroot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-…