将android210改造成Linux210

对比市场上各种cortex-A8开发板,其实我很偏向于买友善的,但友善的mini210有一个致命缺陷——核心版上没有片选线,无法连接自定义的总线设备。为了扩展总线设备,我买了友坚的android210开发板,但这个开发板资料太少了,我想在它上面跑Linux都没有,套件中只有一个Android3.0.8系统,开发手册几乎等于没写,只有Android的开发视频。这下可惨了……

听师兄说过,国内这些做开发板的实际上都是使用的三星公司发布的SDK模板,硬件上基本都是照抄的,没有多大区别。这就让我想到在友坚的系统上跑友善的Linux系统,大不了改造一下试试。

我试过直接从官网下载Linux3.0.x,将其配制成samsungSMDK210,结果启动都启不起来,看来改造的路漫漫呀……

为什么不接用友善已经配置好的内核呢?

于是托蔡辉从同行那里讨来了mini210Linux2.6.35内核,和superboot软件。(文件系统由于太大,且有以前mini6410的,就没要)

通过superboot可以启动内核,但是存在一些问题:

首先LCD屏不亮,网络还连不上,不过CF卡是好的(要不然根本使不了superboot,usb是好的,串口是好的,其他就不知道了……

是不是内核配置不一样?我对比了两家的内核,并按友坚的配置配置了友善原来的内核(当然是做了备分),结果启动还是会死机或者不停地重启,失败……

看来两家的硬件还是有区别的,只好对内核源代码进行手术了……

对比二者的内核源代码,当然差异很大啦,版本都不一样……但最不一样的是arch/arm/mach-s5pv210/mach-mini210.c这个文件(友坚的是mach-sdmkv210.c),重点就是改造这个属于个性订制的文件,以下是我的改造记录

其实LCD屏本身没有多大区别,不亮的原因是背光引脚不一样。一个diff文件(这里也包含了对触摸屏的修改,希望你们能看懂,用Kompare软件应该可以打开):

---friendlyarm/linux-2.6.35.7/arch/arm/mach-s5pv210/mach-mini210.c 2012-02-2718:16:45.000000000 +0800

+++linux-2.6.35.7/arch/arm/mach-s5pv210/mach-mini210.c 2012-08-1715:32:10.209674178 +0800

@@-93,6 +93,8 @@

#include<plat/mfc.h>

#include<plat/iic.h>

#include<plat/pm.h>

+#include<plat/ts.h> //触摸屏用

+//../plat-samsung/include/

#include<plat/sdhci.h>

#include<plat/fimc.h>

@@-597,6 +599,52 @@

pr_err("nomemory for Touchscreen platform data\n");

}

}

+#else //触摸屏用

+staticstruct s3c2410_ts_mach_info s3c_ts_platform __initdata = {

+ .delay =10000,

+ .presc =49,

+ .oversampling_shift =2,

+ .cal_x_max = 800,

+ .cal_y_max = 480,

+ .cal_param = {

+ -13357,-85, 53858048, -95, -8493, 32809514, 65536

+},

+};

+static struct resource s3c_ts_resource[] = {

+[0] = {

+.start = SAMSUNG_PA_ADC,

+ .end = SAMSUNG_PA_ADC + SZ_256 - 1,

+ .flags = IORESOURCE_MEM,

+},

+ [1] = {

+ .start = IRQ_TC,

+ .end = IRQ_TC,

+ .flags = IORESOURCE_IRQ,

+ },

+};

+

+struct platform_device s3c_device_ts = {

+.name = "s3c64xx-ts",

+ .id =-1,

+ .num_resources =ARRAY_SIZE(s3c_ts_resource),

+ .resource =s3c_ts_resource,

+};

+

+void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd)

+ {

+struct s3c2410_ts_mach_info *npd;

+

+if (!pd) {

+printk(KERN_ERR "%s: no platform data\n", __func__);

+return;

+}

+

+npd = kmemdup(pd, sizeof(struct s3c2410_ts_mach_info), GFP_KERNEL);

+if (!npd)

+printk(KERN_ERR "%s: no memory for platform data\n",__func__);

+

+s3c_device_ts.dev.platform_data = npd;

+ }

#endif

#ifdefCONFIG_KEYBOARD_GPIO

@@-878,12 +926,18 @@

/*mDNIe SEL: why we shall write 0x2 ? */

writel(0x2,S5P_MDNIE_SEL);

-

+#if0

/*drive strength to max */

writel(0xaaaaaaaa,S5PV210_GPF0_BASE + 0xc);

writel(0xaaaaaaaa,S5PV210_GPF1_BASE + 0xc);

writel(0xaaaaaaaa,S5PV210_GPF2_BASE + 0xc);

writel(0x000000aa,S5PV210_GPF3_BASE + 0xc);

+#else

+ writel(0xffffffff,S5PV210_GPF0_BASE + 0xc);

+ writel(0xffffffff, S5PV210_GPF1_BASE + 0xc);

+ writel(0xffffffff, S5PV210_GPF2_BASE + 0xc);

+ writel(0x000000ff, S5PV210_GPF3_BASE + 0xc);

+#endif

}

#defineS5PV210_GPD_0_0_TOUT_0 (0x2)

@@-1018,40 +1072,51 @@

//触摸屏用

structs3c_pwm_data pwm_data[] = {

{

-#ifndefCONFIG_MINI210_BUZZER

.gpio_no = S5PV210_GPD0(0),

.gpio_name = "GPD",

.gpio_set_value= S5PV210_GPD_0_0_TOUT_0,

- },{

-#endif

+ },

+{

.gpio_no = S5PV210_GPD0(1),

.gpio_name = "GPD",

.gpio_set_value= S5PV210_GPD_0_1_TOUT_1,

- },{

+ },

+{

.gpio_no = S5PV210_GPD0(2),

.gpio_name = "GPD",

.gpio_set_value= S5PV210_GPD_0_2_TOUT_2,

- },{

+ },

+#ifndefCONFIG_MINI210_BUZZER

+{

+

.gpio_no = S5PV210_GPD0(3),

.gpio_name = "GPD",

.gpio_set_value= S5PV210_GPD_0_3_TOUT_3,

}

+#endif

};

#endif

#ifdefined(CONFIG_BACKLIGHT_PWM)

staticstruct platform_pwm_backlight_data smdk_backlight_data = {

+#if0

.pwm_id = 3,

.max_brightness= 255,

.dft_brightness= 255,

.pwm_period_ns = 25000,

+#else

+ .pwm_id =0,

+ .max_brightness =255,

+ .dft_brightness =192,//128,

+ .pwm_period_ns =50000,//78770,

+#endif

};

staticstruct platform_device smdk_backlight_device = {

.name = "pwm-backlight",

.id = -1,

.dev = {

- .parent= &s3c_device_timer[3].dev,

+ .parent= &s3c_device_timer[0].dev, //3

.platform_data= &smdk_backlight_data,

},

};

@@-1516,6 +1581,7 @@

I2C_BOARD_INFO("s5p_ddc",(0x74>>1)),

},

#endif

+ {I2C_BOARD_INFO("ft5x0x_ts", 0x38), },

};

#ifdefCONFIG_TOUCHSCREEN_GOODIX

@@-1668,10 +1734,10 @@

&s3c_device_mfc,

#endif

-#ifdefCONFIG_TOUCHSCREEN_S3C

+//#ifdefCONFIG_TOUCHSCREEN_S3C //触摸屏用

&s3c_device_ts,

-#endif

- &s3c_device_1wire,

+//#endif

+// &s3c_device_1wire,

#ifdefCONFIG_KEYBOARD_GPIO

&s3c_device_gpio_btns,

#endif

@@-1973,8 +2039,9 @@

#ifdefined(CONFIG_TOUCHSCREEN_S3C)

s3c_ts_set_platdata(&s3c_ts_platform);

+#else

+ s3c24xx_ts_set_platdata(&s3c_ts_platform); //触摸屏用

#endif

-

#ifdefined(CONFIG_S5P_ADC)

s3c_adc_set_platdata(&s3c_adc_platform);

#endif

除此之外,需要将友坚的driver/video/samsung/s3cfb_lte480wv.c拷贝到友善的同名目录下,并修改该目录下的Kconfig文件,在prompt"Select LCD Type"后添加

defaultFB_S3C_LTE480WV

configFB_S3C_LTE480WV

bool"LTE480WV"

dependson (MACH_SMDKV210 || MACH_SMDKC110)

---help---

This enables support for Samsung LTE480WV 4.8\" WVGA LCD panel

Makefile文件中添加:

obj-$(CONFIG_FB_S3C_LTE480WV) +=s3cfb_lte480wv.o

修改

arch/arm/mach-s5pv210/mini210-lcds.c

s3cfb_lcdwvga_s70 里的内容换成(这是根据LTE480WVdatasheet配的时序数据),

staticstruct s3cfb_lcd wvga_s70 = {

.width= 800,

.height= 480,

.p_width= 154,

.p_height= 90,

.bpp= 32,

.freq= 60,

.timing= {

.h_fp= 10,

.h_bp= 78,

.h_sw= 10,

.v_fp= 30,

.v_fpe= 1,

.v_bp= 30,

.v_bpe= 1,

.v_sw= 2,

},

.polarity= {

.rise_vclk= 0,

.inv_hsync= 1,

.inv_vsync= 1,

.inv_vden= 0,

},

};

drivers/char/mini210_pwm.c中的对应定义改为:

#defineBUZZER_PWM_ID 3

#defineBUZZER_PMW_GPIO S5PV210_GPD0(3)

可能还有一些其他的小改动,我也记不清了,主要是这些。

之后就是编译了,相信各位很熟悉.

cpmini210_linux_defconfig .config

makezImage

烧到板子上,一开机,成啦!小企鹅和Qtopia都出来啦。但是触摸屏还是不管用……查了一下,友坚用的是ft5x0x_ts触摸屏,于是下一步的工作就有啦……


移植ft5x0x_ts触摸屏

1、在linux中添加ft5x0x_ts驱动程序

对比友坚和友善的系统内核,同样修改arch/arm/mach-s5pv210/mach-mini210.c文件,上文已述。

将友坚的arch/arm/plat-samsung/include/plat/ts.h文件替换友善的对应文件.

drivers/input/touchscreen/中添加urbetter文件夹,将友坚内核中drivers/urbetter/touchscreen的全部内容拷入该文件夹,并修改ft5x0x_ts.c,不然编译会出错,给各位看的同样是个diff文件:

---android210-kernel/drivers/urbetter/touchscreen/ft5x0x_ts.c 2012-08-1717:01:39.317767802 +0800

+++linux-2.6.35.7/drivers/input/touchscreen/urbetter/ft5x0x_ts.c 2012-08-1717:29:50.342172715 +0800

@@-38,9 +38,13 @@

#include"ft5x0x_ts.h"

-#defineset_irq_type irq_set_irq_type //raymanfeng for kernel 3.0

+//#defineset_irq_type irq_set_irq_type //raymanfeng for kernel 3.0

u8buf[40] = {0};

+#defineGPIO_TS_EINT S5PV210_GPH0(5)

+#defineGPIO_TS_POWER S5PV210_GPH2(3)

+#defineGPIO_TS_WAKE S5PV210_GPH1(7)

+#defineGPIO_TS_COBY_WAKE S5PV210_GPH3(0)

#defineFT_INT_PORT GPIO_TS_EINT

#defineFT_WAKE_PORT GPIO_TS_WAKE

@@-74,7 +78,7 @@

#defineCONFIG_FT5X0X_MULTITOUCH 1

#defineCONFIG_ANDROID_4_ICS 1 //raymanfeng

-externint MmFlag;

+int MmFlag=1; //extern

externspinlock_t lock ;

structts_event {

@@-107,7 +111,8 @@

s_model= 712;

intvalue = 703;

- externchar g_selected_utmodel[];

+ //externchar g_selected_utmodel[];

+ charg_selected_utmodel[32] = {'\0'};

if(sscanf(g_selected_utmodel,"%d", &value) == 1)

{

if(value> 0)

@@-810,7 +815,7 @@

}

#endif //CONFIG_HAS_EARLYSUSPEND

-externint g_touchscreen_init;

+int g_touchscreen_init; //extern

staticint

ft5x0x_ts_probe(structi2c_client *client, const struct i2c_device_id *id)

{

当然还要把它加入到内核编译中,在该文件的上一层目录的Kconfig中添加:

source"drivers/input/touchscreen/urbetter/Kconfig"

在同级的Makefile中添加:

obj-$(CONFIG_TOUCHSCREEN_UT210_FT5X0X) += urbetter/

可能还有些细节我忘了写,但大概就是这样。

别忘了编译的时候选择FT5X0X触摸屏,在menuconfig中的devicedriver->input device->touch screen,勾选"touchscreendriver UT210 FT5X0X"

makezImage

烧写、上电启动,最后会在/dev/input中生成一个event0,这就是我们想要的。验证是不是:

cat/proc/bus/input

验证灵不灵:

cat/dev/input/event0

在触摸屏上点两下,如果有乱码字符出现,就算成功了。


2、为实验触摸屏移植的正确性,我在一个不带Qt的文件系统中移植了tslib1.4(这好像是目前的最高版本),移植方法如下(参考网上的):

$sudo apt-get install autoconf automake libtool

$./autogen.sh

$./configure --prefix=/root/more_space/tslib4arm/ --host=arm-linuxac_cv_func_malloc_0_nonnull=yes

$make

$make install

/root/more_space/tslib4arm/中生成了4个文件夹:bin,etc,include,lib

tslib4arm整个放到ARM文件系统的/opt

/etc/profile中添加:

exportTS_ROOT=/opt/tslib4arm

exportTSLIB_CONSOLEDEVICE=none

exportTSLIB_FBDEVICE=/dev/fb0

exportTSLIB_TSDEVICE=/dev/input/event0

exportTSLIB_CALIBFILE=/etc/pointercal

exportPOINTERCAL_FILE=/etc/pointercal

exportTSLIB_CONFFILE=$TS_ROOT/etc/ts.conf

exportTSLIB_PLUGINDIR=$TS_ROOT/lib/ts

#exportTS_INFO_FILE=/sys/devices/virtual/input/input0/uevent 这句是从友善qtopia中学的,自动检测触摸屏类型,决定使用哪种协议

exportQWS_SIZE=800x480

exportQWS_MOUSE_PROTO="Tslib:/dev/input/event0"

exportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TS_ROOT/lib


修改/opt/etc/ts.conf:

module_rawinput解放,注意首字母前不应有其它任何字符。

启动系统,运行

cd/opt/tslib4arm/bin

./ts_test

结果出现selecteddevice is not a touchscreen I understand的提示

网上找了很多参考意见,问题定位到tslib/plugins/input-raw.cchek_fd的函数,

if(! ((ioctl(ts->fd, EVIOCGVERSION, &version) >= 0) &&

(version== EV_VERSION) &&

(ioctl(ts->fd,EVIOCGBIT(0, sizeof(bit) * 8), &bit) >= 0) &&

(bit& (1 << EV_ABS)) &&

(ioctl(ts->fd,EVIOCGBIT(EV_ABS, sizeof(absbit) * 8), &absbit) >= 0)/* &&

(absbit& (1 << ABS_X)) &&

(absbit& (1 << ABS_Y)) && (absbit & (1 <<ABS_PRESSURE)))*/)) {

fprintf(stderr,"selected device is not a touchscreen I understand\n");


if(ioctl(ts->fd,EVIOCGVERSION, &version) < 0) fprintf(stderr,"ioctl<0\n"); //这些是我后加的

if(version!= EV_VERSION) fprintf(stderr, "version=%d,EV_VERSION=%d\n",version,EV_VERSION);

if(ioctl(ts->fd,EVIOCGBIT(0, sizeof(bit) * 8), &bit) < 0) fprintf(stderr,"ioctl<0\n");

if(!(bit& (1 << EV_ABS))) fprintf(stderr, "bit=0x%x,EV_ABS=0x%x\n",bit,EV_ABS);

if(ioctl(ts->fd,EVIOCGBIT(EV_ABS, sizeof(absbit) * 8), &absbit) < 0)fprintf(stderr, "ioctl<0\n");

if(!(absbit& (1 << ABS_X)) || !(absbit & (1 << ABS_Y)) ||!(absbit & (1 << ABS_PRESSURE)) )

fprintf(stderr,"absbit=0x%x, ABS_X=0x%x, ABS_Y=0x%x,ABS_PRESSURE=0x%x\n",absbit,ABS_X,ABS_Y,ABS_PRESSURE);

return-1;

}

有人说是EV_VERSION与内核中定义的版本不一致,我看了一下,我的是一致的,于是我将所有的导致出现这句话的条件都打印了出来,结果发现是由于

最有一个条件没满足,absbit不对,而改变量来自于ioctl的赋值,哎只好研究一下触摸屏驱动。

这是一款i2c触摸屏,tslib中调用ioctlread,我在他的驱动程序中死活找不到,后来在网上发现是由于LinuxI2C体系结构相当复杂

http://www.cnblogs.com/cute/archive/2011/08/30/2159326.html

这篇文章写的很好,描述了i2clinux中的实现及i2c的协议,看后受益匪浅.

我看到的驱动属于I2C设备驱动层,真正的ioctlreadI2C总线驱动层,具体的定义在/driver/i2c/i2c-dev.c,看来不是没有,而是返回值和要求对应不上。

再研究发现,ts_input_read中读出值的结构是

structtslib_input {

structtslib_module_info module;


int current_x;

int current_y;

int current_p;


int sane_fd;

int using_syn;

};

通过前面的阅读,找到ft5x0x_ts驱动程序中对应的返回结构,

structts_event {

u16 x1;

u16 y1;

u16 x2;

u16 y2;

u16 x3;

u16 y3;

u16 x4;

u16 y4;

u16 x5;

u16 y5;

u16 pressure;

u8 touch_point;

};

靠!返回结构都不一样,能对吗?!问题的原因找到了:我使用的是多触点触摸屏,而tslib的程序是给单触点触摸屏使用的。看来得换tslib,于是在网上搜了一下,不幸的是对多触点的支持,tslib只有一个1.0版本,幸运的是还有一个:

http://sourceforge.net/projects/tslib-mt/

下载,同样的方法编译、使用,只有一点要变:

/opt/etc/ts.confmodule_rawinput变为module_rawmtinput

再试,欧拉!下图为证:


dm9000网卡移植

还有一项要紧的工作——移植网卡,现在的网络不可用,NFS连不上,不论调试还是应用都是个问题,所以还是移上的好。

我对比了一下友坚提供的Linux3.0.8drivers/net/dm9000.c和友善的Linux2.6.35.7对应文件,发现差异还是很大的,看来网卡方面android(或是之后的Linux)还是做了一些改动的,所以我还是使用友善的原版的吧……

还是先改linux/arch/arm/mach-s5pv210/mach-mini210.c这个文件:

---friendlyarm/linux-2.6.35.7/arch/arm/mach-s5pv210/mach-mini210.c 2012-02-2718:16:45.000000000 +0800

+++linux-2.6.35.7/arch/arm/mach-s5pv210/mach-mini210.c 2012-08-2415:17:16.360204015 +0800

@@-93,6 +93,8 @@

@@-763,7 +811,7 @@

#ifdefCONFIG_DM9000

#include<linux/dm9000.h>

-

+#if0

/*physical address for dm9000a ...kgene.kim@samsung.com */

#defineS5PV210_PA_DM9000_A (0x88001000)

#defineS5PV210_PA_DM9000_F (S5PV210_PA_DM9000_A + 0x300C)

@@-849,6 +897,86 @@

s3c_gpio_cfgpin(S5PV210_MP01(1),S3C_GPIO_SFN(2));

gpio_free(S5PV210_MP01(1));

}

+#else

+staticstruct resource smdkv210_dm9000_resources[] = {

+ [0]= {

+ .start =S5P_PA_DM9000,

+ .end =S5P_PA_DM9000 + 0x3,

+ .flags =IORESOURCE_MEM,

+ },

+ [1]= {

+ .start =S5P_PA_DM9000 + 0x4,

+ .end =S5P_PA_DM9000 + 0x7,

+ .flags =IORESOURCE_MEM,

+ },

+ [2]= {

+ .start =IRQ_EINT(10),

+ .end =IRQ_EINT(10),

+ .flags =IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,

+ },

+};

+

+staticstruct dm9000_plat_data smdkv210_dm9000_platdata = {

+ .flags =DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,

+ .dev_addr = { 0x00, 0x09, 0xc0, 0xff, 0xec, 0x48 },

+};

+

+structplatform_device mini210_device_dm9000 = {

+ .name ="dm9000",

+ .id =-1,

+ .num_resources =ARRAY_SIZE(smdkv210_dm9000_resources),

+ .resource =smdkv210_dm9000_resources,

+ .dev ={

+ .platform_data =&smdkv210_dm9000_platdata,

+},

+};

+staticint __init dm9000_set_mac(char *str) {

+ unsignedchar addr[6];

+ unsignedint val;

+ intidx = 0;

+ char*p = str, *end;

+

+ while(*p && idx < 6) {

+ val= simple_strtoul(p, &end, 16);

+ if(end <= p) {

+ /*convert failed */

+ break;

+ }else {

+ addr[idx++]= val;

+ p= end;

+ if(*p == ':'|| *p == '-') {

+ p++;

+ }else {

+ break;

+ }

+ }

+ }

+

+ if(idx == 6) {

+ printk("Setupethernet address to %pM\n", addr);

+ memcpy(smdkv210_dm9000_platdata.param_addr,addr, 6);

+ }

+

+ return1;

+}

+

+__setup("ethmac=",dm9000_set_mac);

+

+staticvoid __init mini210_dm9000_set(void)

+{

+ unsignedint tmp;

+ tmp= __raw_readl(S5P_SROM_BW);

+ tmp&= ~(0xF<<4); /* dm9000 16bit */

+ tmp|= (1<<7) | (1<<6) | (1<<5) | (1<<4);

+ __raw_writel(tmp,S5P_SROM_BW);

+ __raw_writel((0x0<<28)|(0x0<<24)|(0x5<<16)|(0x0<<12)|(0x0<<8)|(0x0<<4)|(0x0<<0),S5P_SROM_BC3);

+

+ tmp= __raw_readl(S5PV210_MP01CON);

+ tmp|= (2 << 4);

+ __raw_writel(tmp,S5PV210_MP01CON);

+

+}

+#endif

#endif

然后注意这里面的S5P_PA_DM9000,是给网卡分配的地址空间,友坚的片选线连的是CSn1,linux/arch/arm/mach-s5pv210/include/mach/map.h中,将

#defineS5PV210_PA_DM9000 (0xA8000000)

#defineS5P_PA_DM9000 S5PV210_PA_DM9000

两行改为(友坚内核提供)

#defineS5PV210_PA_SROM_BANK5 0x88000000

#defineS5P_PA_DM9000 S5PV210_PA_SROM_BANK5 + 0x300

不然的话启动时会出现:

dm9000:read wrong id 0x2b2a2928
dm9000: read wrong id 0x2b2a2928

……(共8行)
dm9000:wrong id: 0x2b2a2928

……

Tryto bring eth0 interface up......ifconfig: SIOCGIFFLAGS: No suchdevice

另外,友坚的和友善的staticvoid dm9000_reset(board_info_t * db)实现方法不一样,应该在makemenuconfig时将CONFIG_DM9000_16BIT置为零,即在devicedrivers-> network device support-> Ethernet (10 or 100Mbit)->DM9000 16-bit 置为n

编译,烧写,运行,会看到

dm9000Ethernet Driver, V1.31

eth0:dm9000a at f0892300,f0896304 IRQ 42 MAC: 00:09:c0:ff:ec:48 (platformdata)

……

Tryto bring eth0 interface up......eth0: link down

ADDRCONF(NETDEV_UP):eth0: link is not ready

Done


Pleasepress Enter to activate this console. eth0: link up, 100Mbps,full-duplex, lpa 0x4DE1

ADDRCONF(NETDEV_CHANGE):eth0: link becomes ready

输入命令,会看到

[root@Lbs/]# ping 192.168.1.17

PING192.168.1.17 (192.168.1.17): 56 data bytes

64bytes from 192.168.1.17: seq=0 ttl=64 time=4.306 ms

64bytes from 192.168.1.17: seq=1 ttl=64 time=0.175 ms

64bytes from 192.168.1.17: seq=2 ttl=64 time=0.172 ms

64bytes from 192.168.1.17: seq=3 ttl=64 time=0.161 ms

……

这样就算成功了。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值