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_countget_group_nameget_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分析相关推荐

  1. VMware发布Linux虚拟桌面技术预览版

    VMware发布Linux虚拟桌面技术预览版 在众多客户的一片呼吁声中,VMware在3月中旬发布了Linux虚拟桌面的技术预览版.从此,用户可以通过VMware Horizon View来建立.发布 ...

  2. 32驱动_轻松掌握pinctrl子系统驱动开发——一个虚拟pinctrl dev驱动开发

    这周主要对pinctrl子系统进行分析,该分析的基本上已经分析完成,唯一没有细说的估计就是gpio与pinctrl之间的关联了.本章即是pinctrl子系统分析的最后一章,本章我们主要实现一个虚拟的p ...

  3. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之Pinctrl子系统和GPIO子系统的使用

    文章目录 前言 1.Pinctrl子系统 1.1.为什么有Pinctrl子系统 1.2.重要的概念 1.3.代码中怎么引用pinctrl 2.GPIO子系统 2.1.为什么有GPIO子系统 2.2.在 ...

  4. RHEV平台中如何在 RED HAT ENTERPRISE LINUX 虚拟机上安装 GUEST 代理和驱动

    使用 Red Hat Enterprise Virtualization Agent 软件仓库所提供的 rhevm-guest-agent 软件包可以在 Red Hat Enterprise Linu ...

  5. 从零开始学Linux内核驱动--(二)简单内核模块驱动程序

    Linux驱动–(二)简单的内核模块驱动程序 一.概述 Linux中所有的驱动都是以内核模块的形式来实现的,他们与其他所有的内核编译在一起形成一个单独的内核镜像文件(所以说Linux是一个宏内核).当 ...

  6. linux虚拟网卡驱动

    之前的前两篇写w5500网卡驱动是我的思路有偏差,用的是一种取巧的方法,在linux的用户空间利用spidev直接进行w5500的设置与tcp连接,这只能叫做是一个w5500的应用程序驱动,虽然能达到 ...

  7. GPT虚拟直播Demo系列(二)|无人直播间实现虚拟人回复粉丝

    摘要 虚拟人和数字人是人工智能技术在现实生活中的具体应用,它们可以为人们的生活和工作带来便利和创新.在直播间场景里,虚拟人和数字人可用于直播主播.智能客服.营销推广等.接入GPT的虚拟人像是加了超强b ...

  8. Kali Linux 安装Nvidia显卡驱动(二)CUDA, Pyrit and Cpyrit-cuda

    1:已增加KaliLinux官方源或其它源后更新. apt-get update && apt-get upgrade -y && apt-get dist-upgra ...

  9. 嵌入式Linux驱动开发(六)pinctrl和gpio子系统实验

    **目的:**简化GPIO驱动开发. ***注意点:***每当配置一个PIN为GPIO时,需要确定该GPIO是否有被别的外设使用.-----------在vscode里对DTS搜索 1. pinctr ...

最新文章

  1. JSON.parseObject(String str)与JSONObject.parseObject(String str)的区别
  2. channelinboundhandler中都包含了哪一类的方法_备考CMA考试有哪些方法技巧?
  3. 线程安全且高效的单例
  4. python接口自动化根据请求接口类型进行封装
  5. 2019/Province_C_C++_A/C/最大降雨量
  6. python查找文字在图片中的位置_图片中的文字竟然能如此快速提取?OCR文字识别功能简直太强大了...
  7. 【LeetCode】390. 消除游戏
  8. Android开发中目前流行控件和知识点总结
  9. 【VirtualBox】设置NAT端口映射-SSH登录
  10. 第五章 线性回归 学习笔记下
  11. python第三项开始每一项都等于前两项的积_Python二十九个常见的脚本汇总!
  12. 基于大数据的城市租房信息可视化分析系统
  13. mac更新完后读取不出移动硬盘的问题解决
  14. office 论文 页码_word如何设置毕业论文页码
  15. Service的绑定过程
  16. SQL中IF函数的使用
  17. 终于懂了汇编代码为什么从键盘上输入字符,将该字符的ASCII显示在屏幕上必须要加30或37(附汇编代码)
  18. 5个私域流量运营方法,教你实现流量变现
  19. No interface expected here
  20. 3 MySQL数据管理

热门文章

  1. Flink 本地安装 构建Flink应用
  2. 计算机网络原理公式,计算机网络原理公式及计算题
  3. Xilinx ISE 14.7与Modelsim10.1a联合仿真
  4. C++11 std::tuple
  5. 【论文翻译】Cross-Calibration of Push-Broom 2D LIDARs and Cameras In Natural Scenes论文学习笔记
  6. 由 GPT 驱动的沙盒,尽情发挥想象力! #NovelAI
  7. 0基础小白用unity+vuforia实现AR随机抽卡/盲盒功能
  8. 易查分如何导入数据?这个最关键的要点别忽略
  9. emqtt服务器 java_手把手教你EMQTT 服务器端
  10. 微信指数告诉你国足现在有多火?