【Linux】虚拟Pinctrl Demo驱动(二) -- Debug FS之Pinctrl分析
1. 前言
我们在调试Pinctrl子系统时,会使用到Debug Filesystem。在/sys/kernel/debug/
目录下就会有pinctrl目录,如果该目录下没有任何目录或文件,说明debugfs功能没有被打开。可以参考这篇博客该功能:《问题一:/sys/kernel/debug/下没有任何文件》
2. DEFINE_SHOW_ATTRIBUTE
我们在kernel内核源码中,经常会发现DEFINE_SHOW_ATTRIBUTE的定义。它具体是什么作用呢?
在Path:Kernel\include\linux\seq_file.h
头文件中,我们找到了它的定义:
通过上面的例子,定义一个DEFINE_SHOW_ATTRIBUTE(pinctrl)
,就相当于实现了如下代码:
#define DEFINE_SHOW_ATTRIBUTE(pinctrl) \
static int pinctrl_open(struct inode *inode, struct file *file) \
{ \return single_open(file, pinctrl_show, inode->i_private); \
} \\
static const struct file_operations pinctrl_fops = { \.owner = THIS_MODULE, \.open = pinctrl_open, \.read = seq_read, \.llseek = seq_lseek, \.release = single_release, \
}
以上可以知,这里定义了一个pinctrl_fops
,它肯定会被其它地方用到。在kernel内核源码中搜索pinctrl_fops
关键字,发现在下面文件中被引用:
Path:Kernel\drivers\pinctrl\core.c
通过系统在调用debugfs_create_file
函数时,就会在/sys/kernel/debug/pinctrl
目录下,创建一个pinctrl-handles文件。
debugfs_create_file("pinctrl-handles", S_IFREG | S_IRUGO, debugfs_root, NULL, &pinctrl_fops);
当系统启动完成后,确实发现了该节点:
所以,当运行cat命令cat /sys/kernel/debug/pinctrl/pinctrl-handles
时,就相当于调用了这些函数:
pinctrl-handles -> pinctrl_open -> pinctrl_show
下面分析在/sys/kernel/debug/pinctrl
目录下,所有节点的实现的功能。
3. pinctrl-handles
在/sys/kernel/debug/pinctrl
目录下的pinctrl-handles,最终会调用pinctrl_show
。
debugfs_create_file("pinctrl-handles", S_IFREG | S_IRUGO, debugfs_root, NULL, &pinctrl_fops);
pinctrl_show会遍历全局的链表头pinctrl_list,它保存着所有使用pinctrl的设备。这里会遍历每个pinctrl device,并打印它每个state的pinctrl_setting。架构大致如下:
static int pinctrl_show(struct seq_file *s, void *what)
{struct pinctrl *p;struct pinctrl_state *state;struct pinctrl_setting *setting;seq_puts(s, "Requested pin control handlers their pinmux maps:\n");mutex_lock(&pinctrl_list_mutex);/* 遍历3个pinctrl:12340000.vt_pinctrl、2290000.iomuxc-snvs和20e0000.iomuxc */list_for_each_entry(p, &pinctrl_list, node) {seq_printf(s, "device: %s current state: %s\n",dev_name(p->dev),p->state ? p->state->name : "none");/* 打印这个pinctrl device的每个state */list_for_each_entry(state, &p->states, node) {seq_printf(s, " state: %s\n", state->name);/* 打印当前state的pinctrl_setting */list_for_each_entry(setting, &state->settings, node) {struct pinctrl_dev *pctldev = setting->pctldev;seq_printf(s, " type: %s controller %s ",map_type(setting->type),pinctrl_dev_get_name(pctldev)); // 打印pinctrl的name,如:12340000.vt_pinctrl、2290000.iomuxc-snvs和20e0000.iomuxc。switch (setting->type) {case PIN_MAP_TYPE_MUX_GROUP:/* 打印pin mux复用模式的pinctrl_setting信息 */pinmux_show_setting(s, setting);break;case PIN_MAP_TYPE_CONFIGS_PIN:case PIN_MAP_TYPE_CONFIGS_GROUP:/* 打印pin config电气特性配置的pinctrl_setting信息 */pinconf_show_setting(s, setting);break;default:break;}}}}mutex_unlock(&pinctrl_list_mutex);return 0;
}
DEFINE_SHOW_ATTRIBUTE(pinctrl);
这里是virt_pinctrl_client.c
驱动使用了pinctrl virtual_i2c,用到了2个pin:VIRT_PINCTRL_PAD_PIN6和VIRT_PINCTRL_PAD_PIN7,并且复用成I2C功能。
4. pinctrl-devices
在/sys/kernel/debug/pinctrl
目录下的pinctrl-devices,最终会调用pinctrl_devices_show
。
debugfs_create_file("pinctrl-devices", S_IFREG | S_IRUGO, debugfs_root, NULL, &pinctrl_devices_fops);
pinctrl_devices_show会遍历所有的pinctrl控制器,这里有3个:12340000.vt_pinctrl、2290000.iomuxc-snvs和20e0000.iomuxc。
static int pinctrl_devices_show(struct seq_file *s, void *what)
{struct pinctrl_dev *pctldev;seq_puts(s, "name [pinmux] [pinconf]\n");mutex_lock(&pinctrldev_list_mutex);/* 遍历所有的pinctrl控制器,如果pmxops和confops就打印yes */list_for_each_entry(pctldev, &pinctrldev_list, node) {seq_printf(s, "%s ", pctldev->desc->name);if (pctldev->desc->pmxops)seq_puts(s, "yes ");elseseq_puts(s, "no ");if (pctldev->desc->confops)seq_puts(s, "yes");elseseq_puts(s, "no");seq_puts(s, "\n");}mutex_unlock(&pinctrldev_list_mutex);return 0;
}
DEFINE_SHOW_ATTRIBUTE(pinctrl_devices);
运行命令cat /sys/kernel/debug/pinctrl/pinctrl-devices
后的效果如下:
5. pinctrl-maps
在/sys/kernel/debug/pinctrl
目录下的pinctrl-maps,最终会调用pinctrl_maps_show
。
debugfs_create_file("pinctrl-maps", S_IFREG | S_IRUGO, debugfs_root, NULL, &pinctrl_maps_fops);
pinctrl_maps_show会遍历全局的链表头pinctrl_maps,它保存着所有使用pinctrl的设备。这里会遍历每个pinctrl device,并打印它每个pinctrl_map。架构大致如下:
static int pinctrl_maps_show(struct seq_file *s, void *what)
{struct pinctrl_maps *maps_node;int i;const struct pinctrl_map *map;seq_puts(s, "Pinctrl maps:\n");mutex_lock(&pinctrl_maps_mutex);/* 遍历全局的链表头pinctrl_maps,它保存着所有使用pinctrl的设备。*/for_each_maps(maps_node, i, map) {seq_printf(s, "device %s\nstate %s\ntype %s (%d)\n",map->dev_name, map->name, map_type(map->type),map->type);if (map->type != PIN_MAP_TYPE_DUMMY_STATE)seq_printf(s, "controlling device %s\n",map->ctrl_dev_name);switch (map->type) {case PIN_MAP_TYPE_MUX_GROUP:/* 打印pin mux复用模式的pinctrl_map信息 */pinmux_show_map(s, map);break;case PIN_MAP_TYPE_CONFIGS_PIN:case PIN_MAP_TYPE_CONFIGS_GROUP:/* 打印pin config电气特性配置的pinctrl_map信息 */pinconf_show_map(s, map);break;default:break;}seq_putc(s, '\n');}mutex_unlock(&pinctrl_maps_mutex);return 0;
}
DEFINE_SHOW_ATTRIBUTE(pinctrl_maps);
运行命令cat /sys/kernel/debug/pinctrl/pinctrl-maps
后的效果如下:
6. 12340000.vt_pinctrl
12340000.vt_pinctrl是上一篇博客《虚拟Pinctrl Demo驱动(一)-- Demo Code》生成的pinctrl控制器。接下来会分析/sys/kernel/debug/pinctrl/12340000.vt_pinctrl
目录下所有节点的作用。
6.1 pinconf-pins
在/sys/kernel/debug/pinctrl/12340000.vt_pinctrl
目录下的pinconf-pins,最终会调用pinconf_pins_show
。
debugfs_create_file("pinconf-pins", S_IFREG | S_IRUGO, devroot, pctldev, &pinconf_pins_fops);
pinconf_pins_show主要是打印该pinctrl每个pin当前的config,这些pin id和pin name信息都保存在struct pinctrl_pin_desc中,然后通过pin id找到pin config的信息并打印出来。
static int pinconf_pins_show(struct seq_file *s, void *what)
{struct pinctrl_dev *pctldev = s->private;unsigned i, pin;seq_puts(s, "Pin config settings per pin\n");seq_puts(s, "Format: pin (name): configs\n");mutex_lock(&pctldev->mutex);/* The pin number can be retrived from the pin controller descriptor */for (i = 0; i < pctldev->desc->npins; i++) {struct pin_desc *desc;pin = pctldev->desc->pins[i].number; // 获取pin iddesc = pin_desc_get(pctldev, pin); // 根据pin id获取struct pin_desc描述符/* Skip if we cannot search the pin */if (!desc)continue;seq_printf(s, "pin %d (%s): ", pin, desc->name);pinconf_dump_pin(pctldev, s, pin); // 根据pin id打印pin config信息seq_putc(s, '\n');}mutex_unlock(&pctldev->mutex);return 0;
}
通过pinconf_dump_pin
间接调用virt_pinctrl_driver.c驱动里面的virt_pinconf_dbg_show
,这里是模拟打印pin mux寄存器和pin config寄存器里面的内容。
static void pinconf_dump_pin(struct pinctrl_dev *pctldev, struct seq_file *s, int pin)
{const struct pinconf_ops *ops = pctldev->desc->confops;if (ops && ops->pin_config_dbg_show)ops->pin_config_dbg_show(pctldev, s, pin);
}static void virt_pinconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin_id)
{struct virt_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);seq_printf(s, "Mux=0x%x Config=0x%x", ipctl->configs[pin_id].mux_mode, ipctl->configs[pin_id].pin_conf);
}static const struct pinconf_ops virt_pinconf_ops = {.pin_config_set = virt_pinconf_set,.pin_config_dbg_show = virt_pinconf_dbg_show,.pin_config_group_dbg_show = virt_pinconf_group_dbg_show,
};
运行命令cat /sys/kernel/debug/pinctrl/12340000.vt_pinctrl/pinconf-pins
后的效果如下:
这里是模拟打印pin mux寄存器和pin config寄存器里面的内容,对于未使用的pin,默认都是0。
6.2 pinconf-groups
在/sys/kernel/debug/pinctrl/12340000.vt_pinctrl
目录下的pinconf-groups,最终会调用pinconf_groups_show
。
debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO, devroot, pctldev, &pinconf_groups_fops);
pinconf_groups_show主要是打印该pinctrl中每个group的pin信息,这些group信息都保存在pin_group_tree中,通过它就可以找到group的每个pin的配置信息。这些配置信息是在pinctrl driver加载时,解析device tree得到的。
static int pinconf_groups_show(struct seq_file *s, void *what)
{struct pinctrl_dev *pctldev = s->private;const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;unsigned ngroups = pctlops->get_groups_count(pctldev); // 获取group的个数,它被定义在virt_pinctrl_driver.c驱动文件里面。unsigned selector = 0;seq_puts(s, "Pin config settings per pin group\n");seq_puts(s, "Format: group (name): configs\n");while (selector < ngroups) {const char *gname = pctlops->get_group_name(pctldev, selector); // 获取group的name,它被定义在virt_pinctrl_driver.c驱动文件里面。seq_printf(s, "%u (%s): ", selector, gname);pinconf_dump_group(pctldev, s, selector, gname); // 打印group中每个pin的配置信息,它被定义在virt_pinctrl_driver.c驱动文件里面。seq_putc(s, '\n');selector++;}return 0;
}
通过pinconf_dump_group
间接调用virt_pinctrl_driver.c驱动里面的virt_pinconf_group_dbg_show
,这里是模拟打印group中pin相关寄存器里面的内容。
static void pinconf_dump_group(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned selector, const char *gname)
{const struct pinconf_ops *ops = pctldev->desc->confops;if (ops && ops->pin_config_group_dbg_show)ops->pin_config_group_dbg_show(pctldev, s, selector);
}static void virt_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,struct seq_file *s, unsigned group){struct group_desc *grp;const char *name;int i;if (group >= pctldev->num_groups)return;seq_puts(s, "\n");grp = pinctrl_generic_get_group(pctldev, group);if (!grp)return;for (i = 0; i < grp->num_pins; i++) {struct virt_pin *pin = &((struct virt_pin *)(grp->data))[i];name = pin_get_name(pctldev, pin->pin);seq_printf(s, " %s: Mux=0x%x Config=0x%x\n", name, pin->config.mux_mode, pin->config.pin_conf);}}static const struct pinconf_ops virt_pinconf_ops = {.pin_config_set = virt_pinconf_set,.pin_config_dbg_show = virt_pinconf_dbg_show,.pin_config_group_dbg_show = virt_pinconf_group_dbg_show,
};static const struct pinctrl_ops virt_pctrl_ops = {.get_groups_count = pinctrl_generic_get_group_count,.get_group_name = pinctrl_generic_get_group_name,.get_group_pins = pinctrl_generic_get_group_pins,.pin_dbg_show = virt_pin_dbg_show,.dt_node_to_map = virt_dt_node_to_map,.dt_free_map = virt_dt_free_map,
};
运行命令cat /sys/kernel/debug/pinctrl/12340000.vt_pinctrl/pinconf-groups
后的效果如下:
6.3 pingroups
在/sys/kernel/debug/pinctrl/12340000.vt_pinctrl
目录下的pingroups,最终会调用pinctrl_groups_show
。
debugfs_create_file("pingroups", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_groups_fops);
pinctrl_groups_show主要是打印保存在pin_group_tree中的group,打印包含group中pin number和pin name的信息。
static int pinctrl_groups_show(struct seq_file *s, void *what)
{struct pinctrl_dev *pctldev = s->private;const struct pinctrl_ops *ops = pctldev->desc->pctlops;unsigned ngroups, selector = 0;mutex_lock(&pctldev->mutex);ngroups = ops->get_groups_count(pctldev); // 获取group的个数seq_puts(s, "registered pin groups:\n");while (selector < ngroups) {const unsigned *pins = NULL;unsigned num_pins = 0;const char *gname = ops->get_group_name(pctldev, selector); // 获取group的nameconst char *pname;int ret = 0;int i;if (ops->get_group_pins)/* 获取当前group中所有的pin的信息 */ret = ops->get_group_pins(pctldev, selector,&pins, &num_pins);if (ret)seq_printf(s, "%s [ERROR GETTING PINS]\n",gname);else {seq_printf(s, "group: %s\n", gname); // 打印group的namefor (i = 0; i < num_pins; i++) {pname = pin_get_name(pctldev, pins[i]); // 获取pin的nameif (WARN_ON(!pname)) {mutex_unlock(&pctldev->mutex);return -EINVAL;}seq_printf(s, "pin %d (%s)\n", pins[i], pname); // 打印pin id和pin name信息}seq_puts(s, "\n");}selector++;}mutex_unlock(&pctldev->mutex);return 0;
}
这些get_groups_count
、get_group_name
和get_group_pins
都被定义在virt_pinctrl_driver.c驱动里面,其实也是调用pinctrl_generic_get_group_count
等公用的内核函数接口,因为这些信息已经保存在了pin_group_tree和num_groups中,所以只有遍历它就可以了。
static const struct pinctrl_ops virt_pctrl_ops = {.get_groups_count = pinctrl_generic_get_group_count,.get_group_name = pinctrl_generic_get_group_name,.get_group_pins = pinctrl_generic_get_group_pins,.pin_dbg_show = virt_pin_dbg_show,.dt_node_to_map = virt_dt_node_to_map,.dt_free_map = virt_dt_free_map,
};
运行命令cat /sys/kernel/debug/pinctrl/12340000.vt_pinctrl/pingroups
后的效果如下:
6.4 pins
在/sys/kernel/debug/pinctrl/12340000.vt_pinctrl
目录下的pins,最终会调用pinctrl_pins_show
。
debugfs_create_file("pins", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_pins_fops);
pinctrl_pins_show主要是打印保存在struct pinctrl_desc中的pins,打印在virt_pinctrl_driver.c驱动定义的中pin number和pin name的信息。
static int pinctrl_pins_show(struct seq_file *s, void *what)
{struct pinctrl_dev *pctldev = s->private;const struct pinctrl_ops *ops = pctldev->desc->pctlops;unsigned i, pin;seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);mutex_lock(&pctldev->mutex);/* The pin number can be retrived from the pin controller descriptor */for (i = 0; i < pctldev->desc->npins; i++) {struct pin_desc *desc;pin = pctldev->desc->pins[i].number; // 获取pin iddesc = pin_desc_get(pctldev, pin); // 根据pin id获取struct pin_desc描述符/* Pin space may be sparse */if (!desc)continue;seq_printf(s, "pin %d (%s) ", pin, desc->name); // 打印pin id和pin name/* Driver-specific info per pin */if (ops->pin_dbg_show)ops->pin_dbg_show(pctldev, s, pin); // pin_dbg_show被定义在virt_pinctrl_driver.c驱动文件里面。seq_puts(s, "\n");}mutex_unlock(&pctldev->mutex);return 0;
}
通过ops->pin_dbg_show
间接调用virt_pinctrl_driver.c驱动里面的virt_pin_dbg_show
,这里只是打印pinctrl device name, 12340000.vt_pinctrl。
static void virt_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,unsigned offset)
{seq_printf(s, "%s", dev_name(pctldev->dev)); // 打印pinctrl device name, 12340000.vt_pinctrl。
}static const struct pinctrl_ops virt_pctrl_ops = {.get_groups_count = pinctrl_generic_get_group_count,.get_group_name = pinctrl_generic_get_group_name,.get_group_pins = pinctrl_generic_get_group_pins,.pin_dbg_show = virt_pin_dbg_show,.dt_node_to_map = virt_dt_node_to_map,.dt_free_map = virt_dt_free_map,
};
运行命令cat /sys/kernel/debug/pinctrl/12340000.vt_pinctrl/pins
后的效果如下:
6.5 pinmux-functions
在/sys/kernel/debug/pinctrl/12340000.vt_pinctrl
目录下的pinmux-functions,最终会调用pinmux_functions_show
。
debugfs_create_file("pinmux-functions", S_IFREG | S_IRUGO, devroot, pctldev, &pinmux_functions_fops);
pinmux_functions_show主要是打印保存在pin_function_tree中的function信息,里面包含了该function包含的group name列表。大致架构如下:
static int pinmux_functions_show(struct seq_file *s, void *what)
{struct pinctrl_dev *pctldev = s->private;const struct pinmux_ops *pmxops = pctldev->desc->pmxops;unsigned nfuncs;unsigned func_selector = 0;if (!pmxops)return 0;mutex_lock(&pctldev->mutex);/* 获取functions的个数,个数保存在struct pinctrl_dev中的num_functions变量中。*/nfuncs = pmxops->get_functions_count(pctldev); while (func_selector < nfuncs) {/* 获取functions的name,个数保存在struct pinctrl_dev的pin_function_tree链表中。* struct function_desc中的name就是function name。*/const char *func = pmxops->get_function_name(pctldev,func_selector);const char * const *groups;unsigned num_groups;int ret;int i;/* 获取保存在pin_function_tree中的group name和group个数 */ret = pmxops->get_function_groups(pctldev, func_selector,&groups, &num_groups);if (ret) {seq_printf(s, "function %s: COULD NOT GET GROUPS\n",func);func_selector++;continue;}/* 打印该function所有的group name */seq_printf(s, "function: %s, groups = [ ", func);for (i = 0; i < num_groups; i++)seq_printf(s, "%s ", groups[i]);seq_puts(s, "]\n");func_selector++;}mutex_unlock(&pctldev->mutex);return 0;
}
运行命令cat /sys/kernel/debug/pinctrl/12340000.vt_pinctrl/pinmux-functions
后的效果如下:
6.6 pinmux-pins
在/sys/kernel/debug/pinctrl/12340000.vt_pinctrl
目录下的pinmux-pins,最终会调用pinmux_pins_show
。
debugfs_create_file("pinmux-pins", S_IFREG | S_IRUGO, devroot, pctldev, &pinmux_pins_fops);
pinmux_pins_show主要是显示pin当前复用成什么功能,未使用的pin会显示UNCLAIMED
。如果被复用成其它功能,会显示哪个驱动使用,哪组配置。
static int pinmux_pins_show(struct seq_file *s, void *what)
{struct pinctrl_dev *pctldev = s->private;const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;const struct pinmux_ops *pmxops = pctldev->desc->pmxops;unsigned i, pin;if (!pmxops)return 0;seq_puts(s, "Pinmux settings per pin\n");if (pmxops->strict)seq_puts(s,"Format: pin (name): mux_owner|gpio_owner (strict) hog?\n");elseseq_puts(s,"Format: pin (name): mux_owner gpio_owner hog?\n");mutex_lock(&pctldev->mutex);/* The pin number can be retrived from the pin controller descriptor */for (i = 0; i < pctldev->desc->npins; i++) {struct pin_desc *desc;bool is_hog = false;pin = pctldev->desc->pins[i].number;desc = pin_desc_get(pctldev, pin);/* Skip if we cannot search the pin */if (desc == NULL)continue;if (desc->mux_owner &&!strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev)))is_hog = true;if (pmxops->strict) {if (desc->mux_owner)seq_printf(s, "pin %d (%s): device %s%s",pin, desc->name, desc->mux_owner,is_hog ? " (HOG)" : "");else if (desc->gpio_owner)seq_printf(s, "pin %d (%s): GPIO %s",pin, desc->name, desc->gpio_owner);elseseq_printf(s, "pin %d (%s): UNCLAIMED",pin, desc->name);} else {/* For non-strict controllers */seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name,desc->mux_owner ? desc->mux_owner: "(MUX UNCLAIMED)",desc->gpio_owner ? desc->gpio_owner: "(GPIO UNCLAIMED)",is_hog ? " (HOG)" : "");}/* If mux: print function+group claiming the pin */if (desc->mux_setting)seq_printf(s, " function %s group %s\n",pmxops->get_function_name(pctldev,desc->mux_setting->func),pctlops->get_group_name(pctldev,desc->mux_setting->group));elseseq_putc(s, '\n');}mutex_unlock(&pctldev->mutex);return 0;
}
运行命令cat /sys/kernel/debug/pinctrl/12340000.vt_pinctrl/pinmux-pins
后的效果如下:
7. 工程代码下载地址
完整的实验工程Demo代码下载地址如下:
https://download.csdn.net/download/ZHONGCAI0901/86734001
【Linux】虚拟Pinctrl Demo驱动(二) -- Debug FS之Pinctrl分析相关推荐
- VMware发布Linux虚拟桌面技术预览版
VMware发布Linux虚拟桌面技术预览版 在众多客户的一片呼吁声中,VMware在3月中旬发布了Linux虚拟桌面的技术预览版.从此,用户可以通过VMware Horizon View来建立.发布 ...
- 32驱动_轻松掌握pinctrl子系统驱动开发——一个虚拟pinctrl dev驱动开发
这周主要对pinctrl子系统进行分析,该分析的基本上已经分析完成,唯一没有细说的估计就是gpio与pinctrl之间的关联了.本章即是pinctrl子系统分析的最后一章,本章我们主要实现一个虚拟的p ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之Pinctrl子系统和GPIO子系统的使用
文章目录 前言 1.Pinctrl子系统 1.1.为什么有Pinctrl子系统 1.2.重要的概念 1.3.代码中怎么引用pinctrl 2.GPIO子系统 2.1.为什么有GPIO子系统 2.2.在 ...
- RHEV平台中如何在 RED HAT ENTERPRISE LINUX 虚拟机上安装 GUEST 代理和驱动
使用 Red Hat Enterprise Virtualization Agent 软件仓库所提供的 rhevm-guest-agent 软件包可以在 Red Hat Enterprise Linu ...
- 从零开始学Linux内核驱动--(二)简单内核模块驱动程序
Linux驱动–(二)简单的内核模块驱动程序 一.概述 Linux中所有的驱动都是以内核模块的形式来实现的,他们与其他所有的内核编译在一起形成一个单独的内核镜像文件(所以说Linux是一个宏内核).当 ...
- linux虚拟网卡驱动
之前的前两篇写w5500网卡驱动是我的思路有偏差,用的是一种取巧的方法,在linux的用户空间利用spidev直接进行w5500的设置与tcp连接,这只能叫做是一个w5500的应用程序驱动,虽然能达到 ...
- GPT虚拟直播Demo系列(二)|无人直播间实现虚拟人回复粉丝
摘要 虚拟人和数字人是人工智能技术在现实生活中的具体应用,它们可以为人们的生活和工作带来便利和创新.在直播间场景里,虚拟人和数字人可用于直播主播.智能客服.营销推广等.接入GPT的虚拟人像是加了超强b ...
- Kali Linux 安装Nvidia显卡驱动(二)CUDA, Pyrit and Cpyrit-cuda
1:已增加KaliLinux官方源或其它源后更新. apt-get update && apt-get upgrade -y && apt-get dist-upgra ...
- 嵌入式Linux驱动开发(六)pinctrl和gpio子系统实验
**目的:**简化GPIO驱动开发. ***注意点:***每当配置一个PIN为GPIO时,需要确定该GPIO是否有被别的外设使用.-----------在vscode里对DTS搜索 1. pinctr ...
最新文章
- JSON.parseObject(String str)与JSONObject.parseObject(String str)的区别
- channelinboundhandler中都包含了哪一类的方法_备考CMA考试有哪些方法技巧?
- 线程安全且高效的单例
- python接口自动化根据请求接口类型进行封装
- 2019/Province_C_C++_A/C/最大降雨量
- python查找文字在图片中的位置_图片中的文字竟然能如此快速提取?OCR文字识别功能简直太强大了...
- 【LeetCode】390. 消除游戏
- Android开发中目前流行控件和知识点总结
- 【VirtualBox】设置NAT端口映射-SSH登录
- 第五章 线性回归 学习笔记下
- python第三项开始每一项都等于前两项的积_Python二十九个常见的脚本汇总!
- 基于大数据的城市租房信息可视化分析系统
- mac更新完后读取不出移动硬盘的问题解决
- office 论文 页码_word如何设置毕业论文页码
- Service的绑定过程
- SQL中IF函数的使用
- 终于懂了汇编代码为什么从键盘上输入字符,将该字符的ASCII显示在屏幕上必须要加30或37(附汇编代码)
- 5个私域流量运营方法,教你实现流量变现
- No interface expected here
- 3 MySQL数据管理
热门文章
- Flink 本地安装 构建Flink应用
- 计算机网络原理公式,计算机网络原理公式及计算题
- Xilinx ISE 14.7与Modelsim10.1a联合仿真
- C++11 std::tuple
- 【论文翻译】Cross-Calibration of Push-Broom 2D LIDARs and Cameras In Natural Scenes论文学习笔记
- 由 GPT 驱动的沙盒,尽情发挥想象力! #NovelAI
- 0基础小白用unity+vuforia实现AR随机抽卡/盲盒功能
- 易查分如何导入数据?这个最关键的要点别忽略
- emqtt服务器 java_手把手教你EMQTT 服务器端
- 微信指数告诉你国足现在有多火?