RK平台WiFi/BT兼容方案

根据模块根据调用check_wifi_chip_type_string函数获取的type来决定WiFi/BT模块的模组厂。其中常见WiFi/BT模组的接口有USB、SDIO以及PCIE。对应的路径如下:

  • USB:/sys/bus/usb/devices;
  • SDIO:/sys/bus/sdio/devices;
  • PCIE:/sys/bus/pci/devices
static const char USB_DIR[] = "/sys/bus/usb/devices";
static const char SDIO_DIR[]= "/sys/bus/sdio/devices";
static const char PCIE_DIR[]= "/sys/bus/pci/devices";
static const char PREFIX_SDIO[] = "SDIO_ID=";
static const char PREFIX_PCIE[] = "PCI_ID=";
static const char PREFIX_USB[] = "PRODUCT=";
int check_wifi_chip_type_string(char *type)
{
	if (identify_sucess == -1) {
        //调用get_wifi_device_id函数获取对应的模组ID,对应的路径:
        // USB接口:/sys/bus/pci/devices;
        // SDIO接口:/sys/bus/sdio/devices;
        // PCIE接口:/sys/bus/pci/devices
		if (get_wifi_device_id(SDIO_DIR, PREFIX_SDIO) == 0)
			ALOGD("%s:%d SDIO WIFI identify sucess",__FUNCTION__,__LINE__);
		else if (get_wifi_device_id(USB_DIR, PREFIX_USB) == 0)
			ALOGD("%s:%d USB WIFI identify sucess",__FUNCTION__,__LINE__);
		else if (get_wifi_device_id(PCIE_DIR, PREFIX_PCIE) == 0)
			PLOG(DEBUG) << "PCIE WIFI identify sucess";
			ALOGD("%s:%d PCIE WIFI identify sucess",__FUNCTION__,__LINE__);
		else {
			ALOGD("%s:%d maybe there is no usb wifi or sdio or pcie wifi,set default wifi module Brocom APXXX",__FUNCTION__,__LINE__);
			//如果上面三种获取不到,则使用默认APXXX
            strcpy(recoginze_wifi_chip, "APXXX");
			identify_sucess = 1 ;
		}
	}

	strcpy(type, recoginze_wifi_chip);
	ALOGE("%s:%d check_wifi_chip_type_string : %s",__FUNCTION__,__LINE__,type);
	return 0;
}

具体是通过get_wifi_device_id函数来获取,接口如下:

typedef struct _wifi_devices
{
  char wifi_name[64];
  char wifi_vid_pid[64];
} wifi_device;
// wifi devices 对应 wifi name和 vid/pid
static wifi_device supported_wifi_devices[] = {
	{"RTL8188EU",	"0bda:8179"},
	{"RTL8188EU",	"0bda:0179"},
	{"RTL8723BU",	"0bda:b720"},
	{"RTL8723BS",	"024c:b723"},
	{"RTL8822BS",	"024c:b822"},
	{"RTL8723CS",	"024c:b703"},
	{"RTL8723DS",	"024c:d723"},
	{"RTL8188FU",	"0bda:f179"},
	{"RTL8822BU",	"0bda:b82c"},
	{"RTL8189ES",	"024c:8179"},
	{"RTL8189FS",	"024c:f179"},
	{"RTL8192DU",	"0bda:8194"},
	{"RTL8812AU",	"0bda:8812"},
	{"RTL8821CS",	"024c:c821"},
    {"RTL8822CU",   "0bda:c82c"},
	{"RTL8822CS",   "024c:c822"},
	{"SSV6051",	    "3030:3030"},
	{"ESP8089",	    "6666:1111"},
	{"AP6354",	    "02d0:4354"},
	{"AP6330",	    "02d0:4330"},
	{"AP6356S",	    "02d0:4356"},
	{"AP6335",	    "02d0:4335"},
	{"AP6255",      "02d0:a9bf"},
	{"RTL8822BE",	"10ec:b822"},
	{"MVL88W8977",	"02df:9145"},
	{"SPRDWL",	    "0000:0000"},
};


int get_wifi_device_id(const char *bus_dir, const char *prefix)
{
	int idnum;
	int i = 0;
	int ret = invalid_wifi_device_id;
	DIR *dir;
	struct dirent *next;
	FILE *fp = NULL;
    //获取支持的模组数组列表数
	idnum = sizeof(supported_wifi_devices) / sizeof(supported_wifi_devices[0]);
    // 根据模组接口类型打开对应的路径
	dir = opendir(bus_dir);
	if (!dir) {
		ALOGE("%s:%d open dir failed: %s",__FUNCTION__,__LINE__,strerror(errno));
		return invalid_wifi_device_id;
	}

	while ((next = readdir(dir)) != NULL) {
		char line[256];
		char uevent_file[256] = {0};
        //将格式化的路径写入到uevent_file,最终路径是:
        // USB接口:/sys/bus/pci/devices/*/uevent;
        // SDIO接口:/sys/bus/sdio/devices/*/uevent;
        // PCIE接口:/sys/bus/pci/devices/*/uevent;
		sprintf(uevent_file, "%s/%s/uevent", bus_dir, next->d_name);
		ALOGD("%s:%d uevent path: %s",__FUNCTION__,__LINE__,uevent_file);
        //读取uevent数据
		fp = fopen(uevent_file, "r");
		if (NULL == fp) {
			continue;
		}

		while (fgets(line, sizeof(line), fp)) {
			char *pos = NULL;
			int product_vid = 0;
			int product_did = 0;
			int producd_bcddev = 0;
			char temp[10] = {0};
            //找到prefix在line中第一次出现位置
			pos = strstr(line, prefix);
			ALOGD("%s:%d line: %s , prefix: %s .",__FUNCTION__,__LINE__,line, prefix);
			if (pos != NULL) {
                //根据路径来获取对应vid和pid
				if (strncmp(bus_dir, USB_DIR, sizeof(USB_DIR)) == 0)
                    //从指定字符串读取特定格式的数据
					sscanf(pos + 8, "%x/%x/%x", &product_vid, &product_did, &producd_bcddev);
				else if (strncmp(bus_dir, SDIO_DIR, sizeof(SDIO_DIR)) == 0)
					sscanf(pos + 8, "%x:%x", &product_vid, &product_did);
				else if (strncmp(bus_dir, PCIE_DIR, sizeof(PCIE_DIR)) == 0)
					sscanf(pos + 7, "%x:%x", &product_vid, &product_did);
				else
					return invalid_wifi_device_id;
                //将vid和pid格式化输出到temp中
				sprintf(temp, "%04x:%04x", product_vid, product_did);
				ALOGD("%s:%d pid:vid : %04x:%04x ",__FUNCTION__,__LINE__,product_vid, product_did);
				for (i = 0; i < idnum; i++) {
                    //读到的pid和支持pid比较确认对应的模组名称
					if (0 == strncmp(temp, supported_wifi_devices[i].wifi_vid_pid, 9)) {
						ALOGE("%s:%d found device pid:vid : %04x:%04x ",__FUNCTION__,__LINE__,product_vid, product_did);
						strcpy(recoginze_wifi_chip, supported_wifi_devices[i].wifi_name);
						identify_sucess = 1 ;
						ret = 0;
						fclose(fp);
						goto ready;
					}
				}
			}
		}
		fclose(fp);
	}

	ret = invalid_wifi_device_id;
ready:
	closedir(dir);
	//PLOG(DEBUG) << "wifi detectd return ret:" << ret;
	ALOGD("%s:%d wifi detectd return ret: %d",__FUNCTION__,__LINE__,ret);
	return ret;
}

至此,可以看出获取wifi模组的过程(以PCIE为例):读取/sys/bus/pci/devices/*/uevent中以“PCI_ID=”开头的数据。然后截取其中的pid,然后所支持的列表的对比,来获取对应的WiFi/BT/模组名称。如果不在列表则为APXXX代替:

//设备上是对应的接口如下
ribeye:/ # cat sys/bus/pci/devices/0002\:21\:00.0/uevent
DRIVER=pcieh
PCI_CLASS=28000
PCI_ID=14E4:4475
PCI_SUBSYS_ID=14E4:4375
PCI_SLOT_NAME=0002:21:00.0
MODALIAS=pci:v000014E4d00004475sv000014E4sd00004375bc02sc80i00

//kernel-5.10/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include/bcmdevs.h
#define BCM4375_CHIP_ID		0x4375          /* 4375 chipcommon chipid */
#define BCM4375_D11AX_ID	0x4475		/* 4375 802.11ax dualband device */

设备日志分析:从日志看,我们设备没有配置对应的芯片所以这里check_wifi_chip_type_string为APXXX

03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:205 uevent path: /sys/bus/pci/devices/./uevent
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:205 uevent path: /sys/bus/pci/devices/../uevent
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:205 uevent path: /sys/bus/pci/devices/0002:21:00.0/uevent
......
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:219 line: DRIVER=pcieh
03-14 10:59:23.488  1724  1724 D wpa_supplicant:  , prefix: PCI_ID= .
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:219 line: PCI_CLASS=28000
03-14 10:59:23.488  1724  1724 D wpa_supplicant:  , prefix: PCI_ID= .
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:219 line: PCI_ID=14E4:4475
03-14 10:59:23.488  1724  1724 D wpa_supplicant:  , prefix: PCI_ID= .
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:232 pid:vid : 14e4:4475 
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:219 line: PCI_SUBSYS_ID=14E4:4375
03-14 10:59:23.488  1724  1724 D wpa_supplicant:  , prefix: PCI_ID= .
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:219 line: PCI_SLOT_NAME=0002:21:00.0
03-14 10:59:23.488  1724  1724 D wpa_supplicant:  , prefix: PCI_ID= .
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:219 line: MODALIAS=pci:v000014E4d00004475sv000014E4sd00004375bc02sc80i00
......
03-14 10:59:23.488  1724  1724 D wpa_supplicant: get_wifi_device_id:253 wifi detectd return ret: -1
03-14 10:59:23.488  1724  1724 D wpa_supplicant: check_wifi_chip_type_string:270 maybe there is no usb wifi or sdio or pcie wifi,set default wifi module Brocom APXXX
03-14 10:59:23.488  1724  1724 I wpa_supplicant: check_wifi_chip_type_string:278 check_wifi_chip_type_string : APXXX

因此,需要在supported_wifi_devices列表中增加我们对应的芯片和vid与pid,其中VID(Vendor ID)表示芯片厂商,DID(Device ID)表示具体的模组型号,对应如下,14e4表示博通芯片,4475表示博通下BCM4375一款芯片。这里遗留一个问题PCIE设备的Vid和Did是如何获取的?

{"AP6275HH3",	"14e4:4475"},

添加后对应的设备日志如下:

03-15 02:27:20.984   478   478 D android.hardware.wifi@1.0-service: get_wifi_device_id:229 pid:vid : 14e4:4475 
03-15 02:27:20.985   478   478 I android.hardware.wifi@1.0-service: get_wifi_device_id:232 found device pid:vid : 14e4:4475 
03-15 02:27:20.985   478   478 D android.hardware.wifi@1.0-service: get_wifi_device_id:248 wifi detectd return ret: 0
03-15 02:27:20.985   478   478 D android.hardware.wifi@1.0-service: check_wifi_chip_type_string:259 PCIE WIFI identify sucess
03-15 02:27:20.985   478   478 I android.hardware.wifi@1.0-service: check_wifi_chip_type_string:268 check_wifi_chip_type_string : AP6275HH3
03-15 02:27:36.957   478   478 E android.hardware.wifi@1.0-service: falied to find wifi driver for type=: Success
03-15 02:27:36.957   478   478 E android.hardware.wifi@1.0-service: Failed to load WiFi driver
03-15 02:27:36.957   478   478 E android.hardware.wifi@1.0-service: Failed to initialize firmware mode controller
03-15 02:27:36.957   478   478 E android.hardware.wifi@1.0-service: Wifi HAL start failed
03-15 02:27:36.957   815  1250 E HalDevMgr: Cannot start IWifi: 9 ()
03-15 02:27:36.957   815  1250 E WifiVendorHal: Failed to start vendor HAL
03-15 02:27:36.957   815  1250 E WifiNative: Failed to start vendor HAL
03-15 02:27:36.957   815  1250 E WifiNative: Failed to start Hal

发现WiFi无法启动,对比正常日志应该是我们修改上面配置后,获取不到对应的module path,driver name,hal 那么等导致的问题。具体代码如下:

typedef struct _wifi_file_name
{
  char wifi_name[64];
  char wifi_driver_name[64];
  char wifi_module_path[128];
  char wifi_module_arg[128];
  char wifi_hal_name[64];
}wifi_file_name;

const wifi_file_name module_list[] =
{
	{"RTL8723BU", RTL8723BU_DRIVER_MODULE_NAME, RTL8723BU_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8188EU", RTL8188EU_DRIVER_MODULE_NAME, RTL8188EU_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8192DU", RTL8192DU_DRIVER_MODULE_NAME, RTL8192DU_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8822BU", RTL8822BU_DRIVER_MODULE_NAME, RTL8822BU_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8822BS", RTL8822BS_DRIVER_MODULE_NAME, RTL8822BS_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8188FU", RTL8188FU_DRIVER_MODULE_NAME, RTL8188FU_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8189ES", RTL8189ES_DRIVER_MODULE_NAME, RTL8189ES_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8723BS", RTL8723BS_DRIVER_MODULE_NAME, RTL8723BS_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8723CS", RTL8723CS_DRIVER_MODULE_NAME, RTL8723CS_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8723DS", RTL8723DS_DRIVER_MODULE_NAME, RTL8723DS_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8812AU", RTL8812AU_DRIVER_MODULE_NAME, RTL8812AU_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8189FS", RTL8189FS_DRIVER_MODULE_NAME, RTL8189FS_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8822BE", RTL8822BE_DRIVER_MODULE_NAME, RTL8822BE_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8821CS", RTL8821CS_DRIVER_MODULE_NAME, RTL8821CS_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8822CU", RTL8822CU_DRIVER_MODULE_NAME, RTL8822CU_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"RTL8822CS", RTL8822CS_DRIVER_MODULE_NAME, RTL8822CS_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, REALTEK_WIFI_HAL},
	{"SSV6051",     SSV6051_DRIVER_MODULE_NAME,   SSV6051_DRIVER_MODULE_PATH, SSV6051_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"ESP8089",     ESP8089_DRIVER_MODULE_NAME,   ESP8089_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"AP6335",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"AP6330",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"AP6354",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"AP6356S",         BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"AP6255",          BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"APXXX",           BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"MVL88W8977",      MVL_DRIVER_MODULE_NAME,       MVL_DRIVER_MODULE_PATH, MVL88W8977_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"RK912",         RK912_DRIVER_MODULE_NAME,     RK912_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},
	{"SPRDWL",          SPRDWL_DRIVER_MODULE_NAME, SPRDWL_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, SPRD_WIFI_HAL},
	{"BES2600",          BES2600_DRIVER_MODULE_NAME, BES2600_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BES_WIFI_HAL},
};

const char *get_wifi_driver_name(void)
{
	if (wifi_type[0] == 0) {
		check_wifi_chip_type_string(wifi_type);
	}
    //对应module list对应wifi_type是否一致
	for (int i = 0; i< (int)(sizeof(module_list) / sizeof(module_list[0])); i++) {
		if (strncmp(wifi_type, module_list[i].wifi_name, strlen(wifi_type)) == 0) {
			ALOGI("%s:%d matched wifi_driver_name:  %s",__FUNCTION__,__LINE__,module_list[i].wifi_driver_name);
			return module_list[i].wifi_driver_name;
		}
	}
	return NULL;
}

const char *get_wifi_module_path(void)
{
	if (wifi_type[0] == 0) {
		check_wifi_chip_type_string(wifi_type);
	}

	for (int i = 0; i< (int)(sizeof(module_list) / sizeof(module_list[0])); i++) {
		if (strncmp(wifi_type, module_list[i].wifi_name, strlen(wifi_type)) == 0) {
			ALOGI("%s:%d matched wifi_module_path:  %s",__FUNCTION__,__LINE__,module_list[i].wifi_module_path);
			return module_list[i].wifi_module_path;
		}
	}
	return NULL;
}

const char *get_wifi_module_arg(void)
{
	if (wifi_type[0] == 0) {
		check_wifi_chip_type_string(wifi_type);
	}
	for (int i = 0; i< (int)(sizeof(module_list) / sizeof(module_list[0])); i++) {
		if (strncmp(wifi_type, module_list[i].wifi_name, strlen(wifi_type)) == 0) {
			ALOGI("%s:%d matched wifi_module_arg:  %s",__FUNCTION__,__LINE__,module_list[i].wifi_module_arg);
			return module_list[i].wifi_module_arg;
		}
	}
	return NULL;
}

const char *get_wifi_hal_name(void)
{
	if (wifi_type[0] == 0) {
		check_wifi_chip_type_string(wifi_type);
	}
	for (int i = 0; i< (int)(sizeof(module_list) / sizeof(module_list[0])); i++) {
		if (strncmp(wifi_type, module_list[i].wifi_name, strlen(wifi_type)) == 0) {
			ALOGI("%s:%d matched wifi_hal_name: %s ",__FUNCTION__,__LINE__,module_list[i].wifi_hal_name);
			return module_list[i].wifi_hal_name;
		}
	}
	return NULL;
}

从代码可以看出,以上接口首先会通过check_wifi_chip_type_string获取到wifi type的名称是module_list中,如果不在在获取为NULL,WiFi将无法加载。我们在没有添加我们对应的vid之前,使用的是默认的名称如下,可以找到对应的MODULE NAME/MODULE_PATH和WIFI HAL。

{"APXXX",           BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},

因此,我们只需要将module_list中也添加我们的module name就可以识别到:

{"AP6275HH3",       BCM_DRIVER_MODULE_NAME,       BCM_DRIVER_MODULE_PATH, UNKOWN_DRIVER_MODULE_ARG, BROADCOM_WIFI_HAL},

添加后对应日志如下:

03-15 06:35:19.596   483   483 I android.hardware.wifi@1.0-service: get_wifi_module_path:295 matched wifi_module_path:  /vendor/lib/modules/bcmdhd.ko
03-15 06:35:19.596   483   483 I android.hardware.wifi@1.0-service: get_wifi_module_arg:309 matched wifi_module_arg:  
03-15 06:35:19.597   483   483 I android.hardware.wifi@1.0-service: get_wifi_hal_name:323 matched wifi_hal_name: libwifi-hal-bcm.so 
03-15 06:35:19.597   483   483 D RKWifiHAL: libwifi hal name: libwifi-hal-bcm.so
03-15 06:35:19.612   483   483 I android.hardware.wifi@1.0-service: check_wifi_chip_type_string:269 check_wifi_chip_type_string : AP6275HH3
03-15 06:35:21.255   464   479 D android.hardware.bluetooth@1.0-service: get_wifi_device_id:230 pid:vid : 14e4:4475 
03-15 06:35:21.255   464   479 I android.hardware.bluetooth@1.0-service: get_wifi_device_id:233 found device pid:vid : 14e4:4475 
03-15 06:35:21.255   464   479 D android.hardware.bluetooth@1.0-service: get_wifi_device_id:249 wifi detectd return ret: 0
03-15 06:35:21.255   464   479 D android.hardware.bluetooth@1.0-service: check_wifi_chip_type_string:260 PCIE WIFI identify sucess
03-15 06:35:21.255   464   479 I android.hardware.bluetooth@1.0-service: check_wifi_chip_type_string:269 check_wifi_chip_type_string : AP6275HH3
03-15 06:35:21.255   464   479 D android.hardware.bluetooth@1.0-impl: Open: libbt-vendor.so
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GitFranc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值