Pinctrl子系统pinctrl_desc结构体进一步介绍

往期内容

本专栏往期内容:

  1. Pinctrl子系统和其主要结构体引入

input子系统专栏:

  1. 专栏地址:input子系统
  2. input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
    – 末片,有往期内容观看顺序

I2C子系统专栏:

  1. 专栏地址:IIC子系统
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    – 末篇,有往期内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    – 末篇,有往期内容观看顺序

img

前言

在上一篇文章中对Pincontroller进行了简单的介绍(Pinctrl子系统和其主要结构体引入),以及对设备树也进行了示范,对Pincontroller的结构体进行的引入,也就是起了个开头,知道了是用pinctrl_dev来指代一个Pincontroller,可以提到了可以通过提供一个pinctrl_desc再去调用某个函数来实现一个pinctrl_dev。那么接下来就进一步讲解。

那么接下来看看pinctrl_dev --> pinctrl_desc *desc --> pinctrl_ops、pinmux_ops、pinconf_ops

1. 作用1:描述、获得引脚 pinctrl_ops

使用pinctrl_ops来操作引脚,主要功能有二:

  • 来取出某组的引脚:get_groups_count、get_group_pins
  • 处理设备树中pin controller中的某个节点:dt_node_to_map,把device_node转换为一系列的pinctrl_mapimg
\Linux-4.9.88\include\linux\pinctrl\pinctrl.hstruct pinctrl_ops {int (*get_groups_count) (struct pinctrl_dev *pctldev);const char *(*get_group_name) (struct pinctrl_dev *pctldev,unsigned selector);int (*get_group_pins) (struct pinctrl_dev *pctldev,unsigned selector,const unsigned **pins,unsigned *num_pins);void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,unsigned offset);int (*dt_node_to_map) (struct pinctrl_dev *pctldev,struct device_node *np_config,struct pinctrl_map **map, unsigned *num_maps);void (*dt_free_map) (struct pinctrl_dev *pctldev,struct pinctrl_map *map, unsigned num_maps);
};

struct pinctrl_ops 结构体定义了全局引脚控制操作(pin control operations),这些操作需要由引脚控制器驱动程序实现。该结构体中的函数指针代表不同的操作接口,允许驱动程序通过这些接口与引脚控制子系统进行交互。

  • get_groups_count: 返回当前已注册的引脚组(pin group)数量。该函数用于获取系统中引脚组的总数。
  • get_group_name: 返回特定引脚组的名称。通过组选择器 selector 作为参数,驱动可以获取某个引脚组的名称。
  • get_group_pins: 返回与特定组选择器对应的引脚数组,并通过参数 pinsnum_pins 返回该数组的指针和引脚数量。此函数用于查询引脚组包含的具体引脚。
  • pin_dbg_show: 可选的 debugfs 显示挂钩,用于在调试文件系统(debugfs)中展示每个引脚的设备相关信息。它可以在调试时提供关于某个引脚的详细信息。
  • dt_node_to_map: 解析设备树(Device Tree)中的 “pin 配置节点” 并为其创建映射表项(mapping table entries)。这些映射表项通过 mapnum_maps 输出参数返回。该函数是可选的,适用于支持设备树的引脚控制器驱动。
  • dt_free_map: 释放通过 dt_node_to_map 创建的映射表项。顶层的 map 指针需要释放,同时还要释放映射表项中动态分配的成员。该函数是可选的,对于不支持设备树的引脚控制器驱动,可以忽略此函数。

这些操作为引脚控制子系统提供了操作引脚组、解析设备树节点、调试显示等功能接口。

2. 作用2:引脚复用 pinmux_ops

img

把某一组引脚配置成某一功能,GPIO模式??或是其它模式

\Linux-4.9.88\include\linux\pinctrl\pinmux.h
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);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;
};

struct pinmux_ops 结构体定义了引脚复用(pinmux)操作,主要用于实现支持引脚复用功能的引脚控制器驱动程序。该结构体提供了一系列回调函数,允许引脚控制器子系统与引脚复用功能进行交互。

  • request: 核心功能调用,用于判断特定的引脚是否可以被用于复用。在实际选择复用设置前,核心会调用该函数来请求引脚。驱动程序可以通过返回负值拒绝该请求。
  • free: 与 request() 相反,释放被请求的引脚。这是在引脚复用完成后释放引脚的回调函数。
  • get_functions_count: 返回当前引脚复用驱动中可选择的复用功能数量。
  • get_function_name: 根据复用选择器 selector 返回某个复用功能的名称。核心通过调用此函数来确定应将某个设备映射到哪个复用设置。
  • get_function_groups: 根据功能选择器 selector 返回与该复用功能相关的引脚组名称数组,并通过 groupsnum_groups 返回受影响的组及其数量。可以与 pinctrl_ops 中的函数结合使用以获取受影响的引脚。
  • set_mux: 启用特定的复用功能与引脚组关联。该函数根据 func_selector 选择特定的复用功能,并根据 group_selector 选择一组引脚进行复用设置。驱动程序不需要检测复用冲突,系统会自动处理引脚冲突。
  • gpio_request_enable: 请求并启用某个引脚的 GPIO 模式。如果引脚控制器支持每个引脚单独复用为 GPIO 模式,则需要实现此函数。参数包括 GPIO 范围和在该范围内的引脚偏移量。
  • gpio_disable_free: 释放之前启用的 GPIO 复用设置,与 gpio_request_enable 作用相反。
  • gpio_set_direction: 对于需要引脚复用的 GPIO 控制器,当 GPIO 配置为输入或输出时可能需要不同的设置。该函数允许控制引脚方向(输入或输出)。
  • strict: 如果为真,则不允许引脚同时作为 GPIO 和复用其他功能使用。在批准引脚请求之前,会严格检查 gpio_ownermux_owner 以防止冲突。

pinmux_ops 提供了驱动与引脚复用子系统之间的交互接口,用于管理引脚复用、GPIO 配置、引脚组和功能的分配。

3. 作用3:引脚配置 pinconf_ops

img

上拉?下拉?等等

\Linux-4.9.88\include\linux\pinctrl\pinconf.h
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONFbool is_generic;
#endifint (*pin_config_get) (struct pinctrl_dev *pctldev,unsigned pin,unsigned long *config);int (*pin_config_set) (struct pinctrl_dev *pctldev,unsigned pin,unsigned long *configs,unsigned num_configs);int (*pin_config_group_get) (struct pinctrl_dev *pctldev,unsigned selector,unsigned long *config);int (*pin_config_group_set) (struct pinctrl_dev *pctldev,unsigned selector,unsigned long *configs,unsigned num_configs);int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,const char *arg,unsigned long *config);void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned offset);void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned selector);void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,struct seq_file *s,unsigned long config);
};

struct pinconf_ops 结构体定义了引脚配置操作,用于支持引脚配置功能的驱动程序实现。它包含一系列函数指针,这些函数用于获取和设置单个引脚及引脚组的配置。

  • is_generic: (可选)如果引脚控制器希望使用通用接口,设置该标志以告诉框架其为通用接口。
  • pin_config_get: 获取特定引脚的配置。如果请求的配置在该控制器上不可用,返回 -ENOTSUPP;如果可用但被禁用,返回 -EINVAL
  • pin_config_set: 配置单个引脚的设置。该函数接受引脚的配置参数和数量,允许驱动程序在特定引脚上设置多个配置。
  • pin_config_group_get: 获取特定引脚组的配置。该函数通过选择器返回整个引脚组的配置,便于一次性读取多个引脚的设置。
  • pin_config_group_set: 配置引脚组内所有引脚的设置。与 pin_config_set 类似,但作用于整个引脚组。
  • pin_config_dbg_parse_modify: (可选)用于调试文件系统的功能,允许修改引脚配置。
  • pin_config_dbg_show: (可选)调试文件系统中的显示钩子,提供特定引脚的设备信息。
  • pin_config_group_dbg_show: (可选)调试文件系统中的显示钩子,提供特定引脚组的设备信息。
  • pin_config_config_dbg_show: (可选)调试文件系统中的显示钩子,解码并显示驱动程序的引脚配置参数。

4. 使用pinctrl_desc注册得到pinctrl_dev

分析的文件:

  • drivers\pinctrl\freescale\pinctrl-imx6ul.c📎pinctrl-imx6ul.c
  • pincontroller的驱动程序文件 。pinctrl-imx.c 文件是 Linux 内核中针对 NXP(之前是 Freescale)i.MX 系列 SoC(系统芯片)的引脚控制器驱动程序实现。这驱动程序通常用于管理和配置 SoC 中的引脚,允许用户和其他系统组件以灵活的方式控制引脚的功能和行为。是一个更通用的驱动,支持多个 i.MX 系列的 SoC。提供了一些基础的、通用的功能或结构,其中关键的是imx_pinctrl_probe函数

imx_pinctrl_probe内部调用了核心层(core.c📎core.c)devm_pinctrl_register(里面又调用了pinctrl_register),就可以根据pinctrl_desc构造出pinctrl_dev,并且把pinctrl_dev放入链表:

\Linux-4.9.88\drivers\pinctrl\freescale\pinctrl-imx.c:
int imx_pinctrl_probe(struct platform_device *pdev,struct imx_pinctrl_soc_info *info)
{struct regmap_config config = { .name = "gpr" }; // 定义寄存器映射配置结构体struct device_node *dev_np = pdev->dev.of_node; // 获取设备的设备树节点struct pinctrl_desc *imx_pinctrl_desc; // 指向 pinctrl 描述符的指针struct device_node *np; // 设备树节点指针struct imx_pinctrl *ipctl; // 指向 i.MX pinctrl 结构的指针struct resource *res; // 资源结构体指针struct regmap *gpr; // 指向寄存器映射的指针int ret, i; // 返回值和循环变量// 检查传入的 pinctrl 信息是否有效if (!info || !info->pins || !info->npins) {dev_err(&pdev->dev, "wrong pinctrl info\n"); // 打印错误信息return -EINVAL; // 返回无效参数错误}info->dev = &pdev->dev; // 将设备指针赋值给 info 结构体// 检查是否有与 GPR 兼容的设备if (info->gpr_compatible) {gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible); // 查找寄存器映射if (!IS_ERR(gpr)) // 如果没有错误regmap_attach_dev(&pdev->dev, gpr, &config); // 绑定寄存器映射到设备}/* 为此驱动程序创建状态持有者等 */ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); // 分配内存用于 ipctl 结构if (!ipctl) // 检查内存分配是否成功return -ENOMEM; // 返回内存不足错误// 检查是否需要使用 SCU(系统控制单元)if (!(info->flags & IMX8_USE_SCU)) {// 为每个引脚分配内存以存储寄存器地址info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *info->npins, GFP_KERNEL);if (!info->pin_regs) // 检查内存分配是否成功return -ENOMEM; // 返回内存不足错误// 初始化每个引脚的寄存器for (i = 0; i < info->npins; i++) {info->pin_regs[i].mux_reg = -1; // 默认多路复用寄存器未定义info->pin_regs[i].conf_reg = -1; // 默认配置寄存器未定义}// 获取平台设备的内存资源res = platform_get_resource(pdev, IORESOURCE_MEM, 0);ipctl->base = devm_ioremap_resource(&pdev->dev, res); // 映射资源到虚拟地址if (IS_ERR(ipctl->base)) // 检查映射是否成功return PTR_ERR(ipctl->base); // 返回映射错误// 检查设备树中是否定义了 "fsl,input-sel" 属性if (of_property_read_bool(dev_np, "fsl,input-sel")) {np = of_parse_phandle(dev_np, "fsl,input-sel", 0); // 解析设备树句柄if (!np) {dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n"); // 打印错误信息return -EINVAL; // 返回无效参数错误}ipctl->input_sel_base = of_iomap(np, 0); // 映射输入选择基地址of_node_put(np); // 释放设备树节点引用if (!ipctl->input_sel_base) {dev_err(&pdev->dev,"iomuxc input select base address not found\n"); // 打印错误信息return -ENOMEM; // 返回内存不足错误}}}// 分配内存用于 pinctrl 描述符imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),GFP_KERNEL);if (!imx_pinctrl_desc) // 检查内存分配是否成功return -ENOMEM; // 返回内存不足错误// 填充 pinctrl 描述符结构体imx_pinctrl_desc->name = dev_name(&pdev->dev); // 设置 pinctrl 名称imx_pinctrl_desc->pins = info->pins; // 设置引脚描述符imx_pinctrl_desc->npins = info->npins; // 设置引脚数量imx_pinctrl_desc->pctlops = &imx_pctrl_ops; // 设置 pinctrl 操作imx_pinctrl_desc->pmxops = &imx_pmx_ops; // 设置 pinmux 操作imx_pinctrl_desc->confops = &imx_pinconf_ops; // 设置 pinconf 操作imx_pinctrl_desc->owner = THIS_MODULE; // 设置模块拥有者// 调用设备树解析函数ret = imx_pinctrl_probe_dt(pdev, info);if (ret) {dev_err(&pdev->dev, "fail to probe dt properties\n"); // 打印错误信息return ret; // 返回错误}// 设置 ipctl 结构中的信息ipctl->info = info;ipctl->dev = info->dev;platform_set_drvdata(pdev, ipctl); // 将 ipctl 数据绑定到平台设备// 注册 pinctrl 设备ipctl->pctl = devm_pinctrl_register(&pdev->dev,imx_pinctrl_desc, ipctl);if (IS_ERR(ipctl->pctl)) {dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); // 打印错误信息return PTR_ERR(ipctl->pctl); // 返回注册错误}dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); // 打印初始化成功信息return 0; // 返回成功
}

可以看到,在其probe函数中主要是去配置pinctrl_desc,然后调用devm_pinctrl_register去构建pinctrl_dev

\Linux-4.9.88\drivers\pinctrl\core.c:
struct pinctrl_dev *devm_pinctrl_register(struct device *dev,struct pinctrl_desc *pctldesc,void *driver_data)
{struct pinctrl_dev **ptr, *pctldev; // 定义指向 pinctrl_dev 的指针// 为资源管理分配内存,大小是指针大小,使用 devm (device managed) 内存管理机制ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) // 检查内存分配是否成功return ERR_PTR(-ENOMEM); // 如果分配失败,返回内存不足错误// 调用 `pinctrl_register()` 注册 pinctrl 控制器pctldev = pinctrl_register(pctldesc, dev, driver_data);if (IS_ERR(pctldev)) { // 检查注册是否成功devres_free(ptr); // 如果注册失败,释放分配的资源return pctldev; // 返回错误指针}// 将注册的 pinctrl_dev 设备保存在资源管理指针中*ptr = pctldev;devres_add(dev, ptr); // 将该资源与设备关联,确保设备卸载时自动释放资源return pctldev; // 返回成功注册的 pinctrl_dev 设备
}

先是分配pinctrl_dev,然后调用pinctrl_register()函数去注册pinctl控制器,来指代一个pincontroller, 核心工作是为设备分配并初始化 pinctrl_dev 结构体,并将其注册到 pin control 子系统中。它通过操作检查确保实现的功能完整,处理 pin 的注册和状态设置

/*** pinctrl_register() - 注册一个 pin 控制器设备* @pctldesc: 描述 pin 控制器的结构体* @dev: 父设备* @driver_data: 驱动程序的私有数据*/
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,struct device *dev, void *driver_data)
{struct pinctrl_dev *pctldev; // 定义 pin 控制器设备结构体指针int ret; // 用于保存函数返回值的变量// 检查输入参数的有效性,如果描述符为空或描述符的名字为空,返回错误指针if (!pctldesc)return ERR_PTR(-EINVAL);if (!pctldesc->name)return ERR_PTR(-EINVAL);// 分配内存为 pin 控制器设备结构体,并初始化为 0pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);if (pctldev == NULL) {dev_err(dev, "failed to alloc struct pinctrl_dev\n"); // 输出分配失败的错误消息return ERR_PTR(-ENOMEM); // 返回内存不足的错误}// 初始化 pin 控制器设备结构体pctldev->owner = pctldesc->owner; // 赋值设备的所有者pctldev->desc = pctldesc; // 关联描述符pctldev->driver_data = driver_data; // 关联驱动私有数据INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); // 初始化 `pin_desc_tree` 为 radix 树,用于描述 pinINIT_LIST_HEAD(&pctldev->gpio_ranges); // 初始化 GPIO 范围的链表pctldev->dev = dev; // 关联设备结构mutex_init(&pctldev->mutex); // 初始化互斥锁// 核查核心操作接口的完整性,确保驱动实现了必要的功能ret = pinctrl_check_ops(pctldev);if (ret) {dev_err(dev, "pinctrl ops lacks necessary functions\n"); // 输出缺少必要操作的错误消息goto out_err; // 如果失败,跳转到错误处理}// 如果实现了 pinmux 操作,检查其操作的完整性if (pctldesc->pmxops) {ret = pinmux_check_ops(pctldev);if (ret)goto out_err;}// 如果实现了 pinconfig 操作,检查其操作的完整性if (pctldesc->confops) {ret = pinconf_check_ops(pctldev);if (ret)goto out_err;}// 注册所有的 pindev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); // 注册 pinsif (ret) {dev_err(dev, "error during pin registration\n"); // 输出 pin 注册失败的错误消息pinctrl_free_pindescs(pctldev, pctldesc->pins, pctldesc->npins); // 如果失败,释放 pin 资源goto out_err; // 跳转到错误处理}// 加入到全局的 pin 控制器设备列表mutex_lock(&pinctrldev_list_mutex);list_add_tail(&pctldev->node, &pinctrldev_list); // 将设备添加到设备列表的尾部mutex_unlock(&pinctrldev_list_mutex);// 获取 pinctrl 句柄pctldev->p = pinctrl_get(pctldev->dev);// 尝试查找并选择设备的默认和睡眠状态if (!IS_ERR(pctldev->p)) {// 查找并选择默认状态pctldev->hog_default = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);if (IS_ERR(pctldev->hog_default)) {dev_dbg(dev, "failed to lookup the default state\n");} else {if (pinctrl_select_state(pctldev->p, pctldev->hog_default))dev_err(dev, "failed to select default state\n");}// 查找睡眠状态pctldev->hog_sleep = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_SLEEP);if (IS_ERR(pctldev->hog_sleep))dev_dbg(dev, "failed to lookup the sleep state\n");}// 初始化 debugfs 调试文件系统pinctrl_init_device_debugfs(pctldev);return pctldev; // 返回注册成功的 pin 控制器设备结构体指针out_err:mutex_destroy(&pctldev->mutex); // 销毁互斥锁kfree(pctldev); // 释放设备结构体内存return ERR_PTR(ret); // 返回错误指针
}
  • 在drivers\pinctrl\freescale\pinctrl-imx6ul.c📎pinctrl-imx6ul.c中注册了平台驱动后,其 probe 先通过设备树匹配找到对应的 pinctrl_info,然后传递给通用的 pinctrl-imx.cprobe 函数。这确保了驱动能够正确识别和初始化针对特定硬件的引脚配置。 所以pinctrl-im6ull.c是通用的。
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{const struct of_device_id *match;struct imx_pinctrl_soc_info *pinctrl_info;match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);if (!match)return -ENODEV;pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;return imx_pinctrl_probe(pdev, pinctrl_info); //这里就是上文中pinctrl-imx.c中定义的
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于OSS搭建在线教育视频课程分享网站

OSS对象存储服务是海量、安全、低成本、高持久的存储服务。适合于存储大规模非结构化数据&#xff0c;如图片、视频、备份文件和容器/虚拟机镜像等。 安装nginx wget https://nginx.org/download/nginx-1.20.2.tar.gz yum -y install zlib zlib-devel gcc-c pcre-devel open…

研究轮腿运动学方案的看法

本文学习自电科中山柳同学的方案分享 遇到的问题&#xff1a; 1、轮毂输出力矩不足以配合腿部收敛机体姿态&#xff08;即腿部关节输出和轮毂输出都被LQR拉大了&#xff0c;但是轮毂最大力矩不够用了&#xff09; 可以引入MPC对LQR输出的反馈增益矩阵K 进行反向增益&#xf…

Linux学习_11

第十章管理Linux的联网 主要包括配置网络&#xff0c;通过域名访问主机&#xff0c;从网站瞎子啊文件&#xff0c;VMware三种网络模式 配置网络 概念 网络接口是指网络中的计算机或网络设备与其他设备实现通讯的进出口&#xff0c;一般是指计算机的网络接口即网卡设备 从RHEL7开…

VBto Converter是一款功能强大的工具,可让您快速轻松地将Microsoft Visual Basic 6.0项目转换

VBto Converter是一款功能强大的工具&#xff0c;可让您快速轻松地将Microsoft Visual Basic 6.0项目转换 1、简介2、官方网站3、本站下载&#xff08;已汉化&#xff09; 1、简介 VBto Converter V2.90 版本&#xff0c;是一款功能强大的工具&#xff0c;可让您快速轻松地将M…

巨好看的登录注册界面源码

展示效果 源码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content"widthdevic…

突破挑战,创新前行 | 生信科技SOLIDWORKS 2025新品发布会·合肥站精彩回顾

2024年10月18日&#xff0c;由生信科技举办的首场SOLIDWORKS 2025新产品发布会在安徽合肥圆满落幕。现场邀请到制造业的专家学者们一同感受SOLIDWORKS 2025最新功能&#xff0c;探索制造业数字化转型之路。 合肥站活动日&#xff0c;由生信科技副总经理徐建开场。他以智造无界&…

【解决方案】微信小程序如何使用 ProtoBuf 进行 WebSocket 通信

前言 故事背景 简单说下背景&#xff0c;项目中需要用 ProtoBuf 协议转换请求参数&#xff0c;并通过 WebSocket 进行双向通信。重点&#xff01;一个是 web端&#xff08;Vue3 TS&#xff09;&#xff0c;一个是微信小程序端&#xff08;原生 JS&#xff09;。 剧情发展 …

Copilot一又成编程助手Top1,GitHub官宣接入Claude+Gemini!OpenAI的Canvas沦为备胎

Copilot一又成编程助手Top1&#xff0c;GitHub官宣接入ClaudeGemini&#xff01;OpenAI的Canvas沦为备胎 &#x1f31f; &#x1f44b; 大家好&#xff0c;我是猫头虎&#xff01;今天带大家来深度解读GitHub Copilot 的最新动态&#xff01;在第十届 GitHub 开发者大会上&…

三周精通FastAPI:24 OAuth2 实现简单的 Password 和 Bearer 验证

官网文档&#xff1a;https://fastapi.tiangolo.com/zh/tutorial/security/simple-oauth2/ OAuth2 实现简单的 Password 和 Bearer 验证 本章添加上一章示例中欠缺的部分&#xff0c;实现完整的安全流。 获取 username 和 password 首先&#xff0c;使用 FastAPI 安全工具获…

Hugging Face | 个人使用笔记

一、网站介绍 模型和数据集都是开源的 搜索模型是默认按照趋势排序的 二、模型具体页面 三、调用API小练习 模型网站&#xff1a;flux-RealismLora 1.点击View Code 获取参考代码 2.创建一个python文件复制进一个代码编辑器 注意&#xff1a;需要补充最后一行保存代码 …

用unity XR interaction Toolkit 制作垃圾分类虚拟仿真项目

项目效果演示&#xff1a; 垃圾分类虚拟仿真项目演示 1.环境配置 选择universal 3D(通用渲染管道)项目&#xff08;不然导入素材包会丢失材质&#xff09;。 选择Window->Package Manager,安装其中的XR interaction Toolkit。 选择其中的Samples,导入Starter Assets。 选择…

基于web的便捷饭店点餐小程序的设计与实现(lw+演示+源码+运行)

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

快速入门HTML

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗 如有错误&#xff0c;欢迎指出~ 目录 第一个html文件 标签 h1~h6 p >段落标签 br > 换行标签 img >图片标签 a >超链接标签 表格标签 表单标签 表单控件 form表单 ⽆语义标签:div&span 综…

【简道云 -注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

C#与C++交互开发系列(十七):线程安全

前言 在跨平台开发和多线程编程中&#xff0c;线程安全是不可忽视的重要因素。C和C#中提供了各自的线程同步机制&#xff0c;但在跨语言调用中&#xff0c;如何确保数据一致性、避免数据竞争和死锁等问题&#xff0c;是开发人员必须考虑的重点。 本文将介绍在C#和C交互开发中确…

docker-minio启动参数

完整命令 docker run -p 9000:9000 -p 9090:9090 -v /opt/minio/data:/data -d --name minio -d --restartalways -e "MINIO_ACCESS_KEYminio" -e "MINIO_SECRET_KEYminioadmin123" minio/minio server --console-address ":9090" -address &…

理解 CSS 中的绝对定位与 Flex 布局混用

理解 CSS 中的绝对定位与 Flex 布局混用 在现代网页设计中&#xff0c;CSS 布局技术如 flex 和绝对定位被广泛使用。然而&#xff0c;这两者结合使用时&#xff0c;可能会导致一些意想不到的布局问题。本文将探讨如何正确使用绝对定位元素&#xff0c;避免它们受到 flex 布局的…

书生大模型实战营 L0 入门岛

书生大模型训练营入门岛任务——训练营链接 1. Linux前置知识 任务&#xff1a;端口转发 当使用vscode远程连接服务器时&#xff0c;在服务器运行的任务&#xff0c;vscode会自动帮忙进行端口映射&#xff0c;方便本地进行访问。 2. Python前置知识 任务1&#xff1a;Leec…

网络搜索引擎Shodan(2)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 声明&#xff1a;本文主要用作技术分享&#xff0c;所有内容仅供参考。任何使用或依赖于本文信息所造成的法律后果均与本人无关。请读者自行判断风险&#xff0c;并遵循相关法律法规。 感谢泷…

Linux 练习三

1、建立用户组 shengcan&#xff0c;其id 为 2000 [rootlocalhost 桌面]# groupadd -g 2000 shengchan 2、建立用户组 caiwu&#xff0c;其id 为 2001 [rootlocalhost 桌面]# groupadd -g 2001 caiwu 3、建立用户组 jishu&#xff0c;其 id 为 2002 [rootlocalhost 桌面]#…