设备树 — platform_device和platform_driver如何让匹配

设备树学习(九、platform_device和platform_driver如何让匹配)   关于这个问题,我之前在分析2.6内核的时候是已经分析过的。 https://blog.youkuaiyun.com/qq_16777851/article/details/81350037   同时在总线驱动模型章节也是从基础知识学习,到最终实现过一个简单的bus的,想要深入学习,最好看下面这个专栏。(基于4.x内核) https://blog.youkuaiyun.com/qq_16777851/colu... 阅读详情

  4.x的内核都是已经支持设备树的,所以platform bus也是做了一些调整。

  主要是在匹配函数里面的支持设备树。

1

2

3

4

5

6

7

8

struct bus_type platform_bus_type = {

    .name       = "platform",

    .dev_groups = platform_dev_groups,

    .match      = platform_match,

    .uevent     = platform_uevent,

    .dma_configure  = platform_dma_configure,

    .pm     = &platform_dev_pm_ops,

};

  

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

/**

 * platform_match - bind platform device to platform driver.

 * @dev: device.

 * @drv: driver.

 *

 * Platform device IDs are assumed to be encoded like this:

 * "<name><instance>", where <name> is a short description of the type of

 * device, like "pci" or "floppy", and <instance> is the enumerated

 * instance of the device, like '0' or '42'.  Driver IDs are simply

 * "<name>".  So, extract the <name> from the platform_device structure,

 * and compare it against the name of the driver. Return whether they match

 * or not.

 */

static int platform_match(struct device *dev, struct device_driver *drv)

{

    struct platform_device *pdev = to_platform_device(dev);

    struct platform_driver *pdrv = to_platform_driver(drv);

  

    /* When driver_override is set, only bind to the matching driver */

    /* 针对特殊情况,dev中的driver_override被设置,则只匹配和driver_override名字相同的驱动程序 */

    if (pdev->driver_override)

        return !strcmp(pdev->driver_override, drv->name);

  

    /* Attempt an OF style match first,设备树方式匹配 */

    if (of_driver_match_device(dev, drv))

        return 1;

  

    /* Then try ACPI style match */

    /* 高级配置和电源管理之类的匹配,这里不是我们这次的重点 */

    if (acpi_driver_match_device(dev, drv))

        return 1;

  

    /* Then try to match against the id table */

    /* 有驱动中有id_table,则dev中的名字和任何一个id_table里面的值匹配就认为匹配 */

    if (pdrv->id_table)

        return platform_match_id(pdrv->id_table, pdev) != NULL;

  

    /* fall-back to driver name match */

    /* 驱动和设备的名字匹配 */

    return (strcmp(pdev->name, drv->name) == 0);

}

  这里可以看到匹配的优先级如下:

  1. 设备里的driver_override被设置,优先级最高。
  2. 驱动里的of_match_table,和平台设备的compatible比较。
  3. 高级配置和电源管理之类的匹配。
  4. platform_driver里的id_table里的所有名字和设备名字匹配。
  5. 最后再是设备名字和驱动名字比较。

  当然除了第一个之外,其它的只要没匹配到,后面的几个匹配还会继续执行的。

设备树匹配方式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

/**

 * of_driver_match_device - Tell if a driver's of_match_table matches a device.

 * @drv: the device_driver structure to test

 * @dev: the device structure to match against

 */

static inline int of_driver_match_device(struct device *dev,

                     const struct device_driver *drv)

{

    return of_match_device(drv->of_match_table, dev) != NULL;

}

  

  

/**

 * of_match_device - Tell if a struct device matches an of_device_id list

 * @ids: array of of device match structures to search in

 * @dev: the of device structure to match against

 *

 * Used by a driver to check whether an platform_device present in the

 * system is in its list of supported devices.

 */

const struct of_device_id *of_match_device(const struct of_device_id *matches,

                       const struct device *dev)

{

    if ((!matches) || (!dev->of_node))

        return NULL;

    return of_match_node(matches, dev->of_node);

}

  

  

  

/**

 * of_match_node - Tell if a device_node has a matching of_match structure

 *  @matches:   array of of device match structures to search in

 *  @node:      the of device structure to match against

 *

 *  Low level utility function used by device matching.

 */

const struct of_device_id *of_match_node(const struct of_device_id *matches,

                     const struct device_node *node)

{

    const struct of_device_id *match;

    unsigned long flags;

  

    raw_spin_lock_irqsave(&devtree_lock, flags);

    match = __of_match_node(matches, node);

    raw_spin_unlock_irqrestore(&devtree_lock, flags);

    return match;

}

  

static

const struct of_device_id *__of_match_node(const struct of_device_id *matches,

                       const struct device_node *node)

{

    const struct of_device_id *best_match = NULL;

    int score, best_score = 0;

  

    if (!matches)

        return NULL;

  

    //根据匹配的分数,选择最高分的是最佳匹配

    for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {

        score = __of_device_is_compatible(node, matches->compatible,

                          matches->type, matches->name);

        if (score > best_score) {

            best_match = matches;

            best_score = score;

        }

    }

  

    return best_match;

}

  

  

  

/**

 * __of_device_is_compatible() - Check if the node matches given constraints

 * @device: pointer to node

 * @compat: required compatible string, NULL or "" for any match

 * @type: required device_type value, NULL or "" for any match

 * @name: required node name, NULL or "" for any match

 *

 * Checks if the given @compat, @type and @name strings match the

 * properties of the given @device. A constraints can be skipped by

 * passing NULL or an empty string as the constraint.

 *

 * Returns 0 for no match, and a positive integer on match. The return

 * value is a relative score with larger values indicating better

 * matches. The score is weighted for the most specific compatible value

 * to get the highest score. Matching type is next, followed by matching

 * name. Practically speaking, this results in the following priority

 * order for matches:

 *

 * 1. specific compatible && type && name

 * 2. specific compatible && type

 * 3. specific compatible && name

 * 4. specific compatible

 * 5. general compatible && type && name

 * 6. general compatible && type

 * 7. general compatible && name

 * 8. general compatible

 * 9. type && name

 * 10. type

 * 11. name

 */

static int __of_device_is_compatible(const struct device_node *device,

                     const char *compat, const char *type, const char *name)

{

    struct property *prop;

    const char *cp;

    int index = 0, score = 0;

  

    /* Compatible match has highest priority */

    /* compatible 匹配有限即最高,匹配到了,则给的分数相对较高 */

    if (compat && compat[0]) {

        prop = __of_find_property(device, "compatible", NULL);

        for (cp = of_prop_next_string(prop, NULL); cp;

             cp = of_prop_next_string(prop, cp), index++) {

            if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {

                score = INT_MAX/2 - (index << 2);

                break;

            }

        }

        if (!score)

            return 0;

    }

  

    /* Matching type is better than matching name,类型匹配会加2分 */

    if (type && type[0]) {

        if (!device->type || of_node_cmp(type, device->type))

            return 0;

        score += 2;

    }

  

    /* Matching name is a bit better than not,最后在确认名字匹配加1分 */

    if (name && name[0]) {

        if (!device->name || of_node_cmp(name, device->name))

            return 0;

        score++;

    }

  

    return score;

}

  看这句 prop = __of_find_property(device, "compatible", NULL);
  可以发先追溯到底,是利用"compatible"来匹配的,即设备树加载之后,内核会自动把设备树节点转换成 platform_device这种格式,同时把名字放到of_node这个地方。

  id_tabel是根据id_table表中的每一个和设备名字进行匹配,这样一个驱动可以支持多个名称的设备。

1

2

3

4

5

6

7

8

9

10

11

12

13

static const struct platform_device_id *platform_match_id(

            const struct platform_device_id *id,

            struct platform_device *pdev)

{

    while (id->name[0]) {

        if (strcmp(pdev->name, id->name) == 0) {

            pdev->id_entry = id;

            return id;

        }

        id++;

    }

    return NULL;

}

  

举例:

  1.ti的omap8250驱动可以支持好多个型号的芯片,其它芯片只要这个的驱动基础上做很小的改动就可通用。

  其中的改动点,使用of_device_id 的date表示的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

/*

 * Struct used for matching a device

 */

struct of_device_id {

    char    name[32];

    char    type[32];

    char    compatible[128];

    const void *data;

};

  

  

  

static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE;

static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;

static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE;

  

  

static const struct of_device_id omap8250_dt_ids[] = {

    { .compatible = "ti,am654-uart" },

    { .compatible = "ti,omap2-uart" },

    { .compatible = "ti,omap3-uart" },

    { .compatible = "ti,omap4-uart", .data = &omap4_habit, },

    { .compatible = "ti,am3352-uart", .data = &am3352_habit, },

    { .compatible = "ti,am4372-uart", .data = &am3352_habit, },

    { .compatible = "ti,dra742-uart", .data = &dra742_habit, },

    {},

};

  

  

static struct platform_driver omap8250_platform_driver = {

    .driver = {

        .name       = "omap8250",

        .pm     = &omap8250_dev_pm_ops,

        .of_match_table = omap8250_dt_ids,

    },

    .probe          = omap8250_probe,

    .remove         = omap8250_remove,

};

  

2.ad5380有好多中类型,芯片使用完全兼容。可能就是版本差异。驱动可以完全兼容。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

static const struct spi_device_id ad5380_spi_ids[] = {

    { "ad5380-3", ID_AD5380_3 },

    { "ad5380-5", ID_AD5380_5 },

    { "ad5381-3", ID_AD5381_3 },

    { "ad5381-5", ID_AD5381_5 },

    { "ad5382-3", ID_AD5382_3 },

    { "ad5382-5", ID_AD5382_5 },

    { "ad5383-3", ID_AD5383_3 },

    { "ad5383-5", ID_AD5383_5 },

    { "ad5384-3", ID_AD5380_3 },

    { "ad5384-5", ID_AD5380_5 },

    { "ad5390-3", ID_AD5390_3 },

    { "ad5390-5", ID_AD5390_5 },

    { "ad5391-3", ID_AD5391_3 },

    { "ad5391-5", ID_AD5391_5 },

    { "ad5392-3", ID_AD5392_3 },

    { "ad5392-5", ID_AD5392_5 },

    { }

};

MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);

  

static struct spi_driver ad5380_spi_driver = {

    .driver = {

           .name = "ad5380",

    },

    .probe = ad5380_spi_probe,

    .remove = ad5380_spi_remove,

    .id_table = ad5380_spi_ids,

};

  最后总结一下有了设备树前后,设备驱动怎么写

  有了设备树这样在dts中编写

1

2

3

4

samsung-beep{

         compatible = "samsung,beep";

         reg = <0x114000a0 0x4 0x139D0000 0x14>;

};

  a -- samsung-beep 为节点名,符合咱们前面提到的节点命名规范;

      我们通过名字可以知道,该节点描述的设备是beep, 设备名是samsung-beep;

  b -- compatible = "samsung,beep"; compatible 属性, 即一个字符串;

      前面提到,所有新的compatible值都应使用制造商的前缀,这里是samsung

  c -- reg = <0x114000a0 0x4 0x139D0000 0x14>;

       reg属性来将地址信息编码进设备树,表示该设备的地址范围;这里是我们用到的寄存器及偏移量;
 

之前在mach-xxx.c中编写

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

static struct  resource beep_resource[] =

{

    [0] = {

        .start = 0x114000a0,

        .end = 0x114000a0+0x4,

        .flags = IORESOURCE_MEM,

    },

    [1] = {

        .start = 0x139D0000,

        .end = 0x139D0000+0x14,

        .flags = IORESOURCE_MEM,

    },

};

static struct platform_device hello_device=

{

    .name = "beep",

    .id = -1,

    .dev.release = hello_release,

    .num_resources = ARRAY_SIZE(beep_resource ),

    .resource = beep_resource,

};

硬件驱动中platform机制及其设备树 这样就形成了驱动的分离,一边是SOC的硬件资源,另一边是用户设备,它们通过统一的接口来连接。驱动分离的思想带来了许多好处,linux长久的发展中,省去了很多冏余的代码,SOC厂家根据统一的接口提供SOC片上外设的驱动,设备厂家也根据结构统一的接口提供设备的驱动,用户需要选择好SOC和外设,就能径方便的关联到一起。这样的思想也延续到了单个SOC中,片上驱动和设备驱动通过总线协议来关联。当我们往内核中添加驱动时,总线就会查找对应的设备,添加设备时就去查找对应的驱动。 这就是linux 中的bus、driver、 阅读详情

相关推荐

ATE测试的未来:自动化与智能化的技术演进

本文探讨了自动测试设备(ATE)在半导体产业中的技术演进,重点关注自动化与智能化的发展趋势。随着芯片制程的不断进步,ATE面临测试复杂度激增和成本压力等挑战。文章分析了AI技术在测试优化中的应用,如自适应测试和缺陷预测,以及模块化架构和端到端测试生态系统的创新。这些技术突破显著提升了测试效率和设备利用率,为半导体测试的未来发展指明了方向。

weixin_29232507的博客 614

设备树与驱动的关系

在没有引入设备树之前,如(linux3.0.35),硬件的配置基本都放在板级文件中,内容很繁杂,修改起来也不方便,可移植性差

二进制模----细微行动改变影响世界 2260

Ubuntu22.04安装ROS1

代表使用 2 线程进行编译,可以根据 CPU 适当调整。如果出现小乌龟窗口,说明安装成功 🎉!启动成功,则打开另一个终端,测试。需要解决一些兼容性问题,因为。由于 Ubuntu 22.04。过程,确保成功安装。

asafriend的博客 4647

在Linux中设备树是怎么和驱动程序联系起来的?

本文以i.MX6ULL为例讲解一下Linux驱动是如何读取DTS并使用DTS文件的。

让技术没有门槛 3432

Allegro PCB设计小技巧:如何用Shift键快速平移复制走线和过孔?

本文深入解析了Allegro PCB设计中利用Shift键进行平移复制的核心技巧。通过对比传统复制粘贴流程,详细演示了如何高效、精准地批量复制走线和过孔,尤其适用于创建等间距电源总线、过孔阵列等场景,能显著提升PCB设计效率与准确性。

pz89012345的博客 554

【自然语言处理(NLP)实战】LSTM网络实现中文文本情感分析(手把手与教学超详细)

在当今数字化时代,人们在社交媒体、评论平台以及各类在线交流中产生了海量的文本数据。这些数据蕴含着丰富的情感信息,从而成为了深入理解用户态度、市场趋势,甚至社会情绪的宝贵资源。自然语言处理(NLP)的发展为我们提供了强大的工具,使得对文本情感进行分析成为可能。在这个领域中,长短时记忆网络(LSTM)凭借其能够捕捉文本序列中长距离依赖关系的能力,成为了情感分析任务中的一项重要技术。通过详细的步骤和示例代码,深入了解如何处理中文文本数据、构建LSTM模型、进行训练和评估。

halo的博客 2万+

设备树匹配内核匹配驱动程序的理解

使用设备树时,给驱动程序调用的过程 我们把设备树.dts 变成plantform_device的资源 过程一步步了解清楚 吃

weixin_43898067的博客 5372

Android Profiler实战:如何用CPU分析工具揪出卡顿元凶(附线程状态解读)

本文深入解析Android Profiler中的CPU分析工具,重点聚焦线程活动监控。通过解读线程状态时间轴上的绿、黄、灰三色含义,并结合实战案例,指导开发者精准定位导致界面卡顿的CPU密集型或I/O阻塞代码,有效提升应用性能与用户体验。

weixin_29197699的博客 372

linux开发之设备树七、设备树下platform_device和platform_driver匹配

device和driver会通过名字进行匹配,匹配成功以后,会执行driver中的probe函数,在这个probe函数中就可以实现去device中取出硬件信息的方法了。设备树替换掉了device部分,也就是设备树也会被转换为platform_device,然后就会通过名字匹配driver,匹配成功后就是调用driver中的probe函数了,然后就是获取硬件信息。

qq_40170041的博客 576

初学者入门机器学习 (ML)的推荐教程

了解基本的机器学习概念并不难。有大量免费的在线博客文章、视频和编码教程可以引导您了解基础知识——从介绍性内容到常见应用程序,再到算法和应用技能。这篇文章总结了一些用于介绍 ML 的最佳免费选项。它按逻辑顺序排列,每个概念都建立在上一个概念的基础上。

u010542847的博客 4621

【AI】获取各类AI大模型api-key的快速教程(OpenAI、Gemini、Claude、DeepSeek)

【AI】获取各类AI大模型api-key的快速教程(OpenAI、Gemini、Claude、DeepSeek)

funfan的博客 3010

基于设备树动态创建的 platform_device和platform_driver 的平台总线(platform bus)匹配机制

对于设备树节点的标准属性,内核把属性放在struct resource和总线设备驱动框架下的platform_device一致,仍可通过platform_get_resource()获取。of_match_table指针指向驱动可支持的设备,将 const struct of_device_id *of_match_table;其中的 compatile="ohhh";其中:内核对device_node(设备树中的节点)→platform_device的处理只是针对满足条件的device_node。

weixin_60725397的博客 886

【图像去噪】基于加权核范数最小化算法实现图像去噪附matlab代码

1 简介 WNNM是一种约束矩阵奇异值稀疏性的低秩算法,在NNM理论基础上增加了核范数权重,有效利用了自然图像的先验信息并提高了核范数的灵活性. 2 部分代码 ​clcclear allclose allnSig = 100;O_Img = double(imread('Monarch.png'));​randn('seed', 0);N_Img = O_Img + nSig* randn(size(O_Img)); ..

qq_59747472的博客 3117

3.6内核对设备树的处理——platform_device跟platform_driver的匹配

platform_device跟platform_driver的匹配

一个嵌入式软件工程师的博客 1614

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

内核对设备树的处理__platform_device跟platform_driver的匹配

内核对设备树的处理__platform_device跟platform_driver的匹配

C/C++、嵌入式开发、深度学习算法、模型部署与推理优化 438

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

点亮MIPI屏;系统启动失败-无法启动根文件系统;启动设备树下 platform_device 和 platform_driver 匹配实验

改.dts” 是解决板级设备节点配置的正确方向,且能规避之前的.dtsi引用问题,但 “语法正确” 只是第一步。需同时满足 “属性合规、无资源冲突、编译配置正确、驱动匹配”,才能确保修改后编译生效。点亮mipi屏幕点亮MIPI屏幕打开设备树文件:打开这个/** 屏幕选择* ATK_LCD_TYPE_MIPI_720P: 正点原子5.5寸 720*1280 MIPI屏* ATK_LCD_TYPE_MIPI_1080P: 正点原子5.5寸 1080*1920 MIPI屏。

weixin_57340941的博客 770

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Linux dts设备树和platform驱动详解

概念 小麦大叔 2019-05-06 22:56:31 12603 收藏 135 什么是设备树 dts(device tree)? 设备树(Device Tree)是描述计算机的特定硬件设备信息的数据结构,以便于操作系统的内核可以管理和使用这些硬件,包括CPU或CPU,内存,总线和其他一些外设。dtb文件会被保存到ROM中,最终通过bootbolader被加载到内核,这样内核就可以通过解析设备树来让驱动去控制实际的硬件了。 设备树是通过Open Firmware项目从基于SPARC的工作站和服务器派生而来的

qq_43491149的博客 1万+

驱动-设备树和驱动自动匹配

前面通过设设备树了解过设备树语法、中断、时钟、GPIO、pinctrl,设备树描述设备属性,同时部分硬件设备描述放在设备树里面。对于硬件外设等接口放到设备树中,在平台总线篇章 是需要驱动和设备匹配的。那么现在的问题就是如何在设备树中描述硬件信息,驱动起来后自动和设备树中的设备匹配起来,建立通信桥梁?这里我们终于从之前了解的设备树属性关联延伸到具体设备树到设备的实战了解了设备树到device及device和driver 匹配过程。

十年饮冰,难凉热血 1750

设备树如何转化为platform_device:内核匹配机制与驱动加载全解析

本文详细解析Linux内核中设备树(DTS)转换为platform_device的完整流程与匹配机制。重点阐述compatible属性的核心作用、四种设备驱动匹配策略的优先级与应用场景,并提供实际开发中的调试技巧与常见问题解决方案,帮助开发者深入理解设备树与驱动的协同工作方式。

t8u9v0的博客 711

设备树和Platform架构--6-platform_driver及match

1 概述 (1)Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。这个属于分离的思想,将设备和驱动分开管理。 (2)Platform总线仅仅时诸多总线中的一种。platform总线的设计初衷:见《设备树和Platform架构--4--platform bus概述及其初始化》 (3)在设备树为引入到li...

huofengfeihu的博客 1090

platform总线、设备与驱动

Linux设备驱动开发详解:基于最新的Linux 4.0内核 (宋宝华)》一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、PC、SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,在SoC系统中集成的独立外设控制器、挂接在SoC内存空间的外设等却不依附于此类总线。基于这一背景,相应的设备称为,而驱Linux发明了一种虚拟的总线,称为platform总线,而驱动成为。,而它们本身就是字符设备。

张哈哈的博客 1093

platform平台驱动模型简述(linux驱动开发篇)

此篇是驱动分离(总线、驱动和设备模型)的应用扩展,主要简述platform平台 1. platform总线 总线(IIC、SPI、USB等),platform应该叫做虚拟总线 /****************************** ***bus_type结构体表示总线******* ******************************/ struct bus_type { const char *name; /* 总线名字

栋哥修炼日记 3528

如何理解驱动程序、设备树、platform、device、driver之间的关系

理解驱动程序、设备树、platform、device、driver之间的关系,学习利用设备树来使用或者编写驱动程序

weixin_42408707的博客 6532

3.6platform_device和platform_driver如何让匹配

分析 主要是在匹配函数里面的支持设备树。 struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .dma_configure = ...

qq_34738528的博客 189
上一篇: C 语言printf打印各种数据类型的方法(u8/s8/u16/s16.../u64/double/float)
下一篇: linux中sysfs创建设备节点的方法和DEVICE_ATTR
mtOS1573
博客等级 码龄15年 305粉丝 188原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值