solaris驱动开发

驱动开发步骤:

1       创建开发目录和文件

创建驱动程序文件。

2       编写可加载模块配置的入口点

即初始化和卸载。

int  _init(void)  

_init入口点首先调用ddi_soft_state_init函数来初始化软状态,若失败则返回错误代码,若成功,_init调用mod_install加载新模块,若加载失败调用ddi_soft_state_fini并返回失败模块安装的错误代码。

int _info(structmodinfo *modinfop).

_info入口点调用mod_info(&ml, modinfop)返回可加载模块信息。

int _fini(void)

_fini入口点调用mod_remove删除_init入口点所安装的模块及撤销设备所有实例的状态指针和状态结构。

3       编写自动配置入口点

实现驱动模块连接和卸载

static int wrmod_attach()

_attach()入口点首先调用ddi_get_instance()来检索设备信息节点的实例号,该实例号用来调用ddi soft state zalloc () 、ddi getsoft state () 和ddi create minor node ( )等其它函数。

static int wrmod_detach()

detach 必须调用ddi remove minor node() 来解除ddi create minornode () 所分配的一

切. 并且必须撤消wrmod attach () 例程做过的每一件事.

static int wrmod getinfo( dev_info_t *dip , ddi_info_cmd_t cmd , void *arg , void  *resultp) / *通过其参数之一返回被请求的设备驱动程序信息.* /

4       编写用户上下文入口点

实现打开关闭设备,获取模块信息等

wrmod open ( dev_t*devp ,int flag ,int otyp ,cred_t * credp)

{

int instance = getminor ( * devp) ;

if ( ( qsp = ddi get soft state ( ) )= =NULL)

ASSERT(qsp - > instance = =instance) ;

}/ * 例程获得对设备访问权. * /

wrmod close (dev t dev ,int flag ,int otyp , cred t * credp)

/* 放弃对设备访问,close ( ) 例程必须撤消open () 例程所做的每一件事. * /

static int wrmod read(dev_t dev ,st ruct uio* uiop ,cred_t * credp) / * 从设备节点读取数

据. * /

static int wrmod write(dev t dev ,st ruct uiocred t * credp) / * 将数据写到设备节

点. * /

5       定义数据结构

所有驱动程序都必须定义一个设备操作结构dev_ops。由于dev_ops结构包含了一个指向cb_ops 字符和块操作结构的指针,因此必须先定义字符和块操作结构cb_ops。可加载驱动程序的modldrv连接结构包含一个指向dev_ops结构的指针. modlinkage模块连接结构包含一个指向modldrv结构的指针. 在这些数据结构中初始化入口点使驱动程序可被动态加载. wrmod相关入口点如图3 所示.

6       创建驱动程序配置文件

7       构建和安装驱动程序

Ø  编译和链接驱动程序

使用-D _KERNAL选项表示该代码用于定义内核模块,DEBUG选项用于ASSERT()语句。

在32位X86架构类似于$cc –D _KERNAL –DDEBUG –c dummy.c $ld –r –o dummy dummy.o。

在64位X86架构solaris系统中需要使用sun studio中bin目录下的cc 和 /usr/bin/amd64/的ld才可以编译连接成功。

命令为:

cc -D_KERNEL -m64 -xarch=sse2a-xmodel=kernel -c dummy.c

ld –r –o dummy dummy.o

请参照http://download.oracle.com/docs/cd/E24847_01/html/819-7057/loading-1.html#scrolltoc

Ø  在调试的时候可以在临时位置(tmp)放置驱动程序,在/drv目录(64位/usr/kernel/drv/amd64)下建立到tmp/dummy的连接。等调式完成后再将驱动程序拷贝到/usr/kernal/drv目录下(64位驱动需要拷贝到/usr/kernel/drv/amd64目录下),配置文件(conf)不管32位还是64位都要拷贝到/usr/kernel/drv目录下。

cp dummy  /tmp//拷贝驱动到tmp

在64位的X86架构上建立连接

ln -s /tmp/dummy /   usr/kernel/drv/amd64/dummy

在32位的X86架构上建立连接

ln -s /tmp/dummy /   usr/kernel/drv/dummy

cp dummy.conf /usr/kernel/drv//拷贝配置文件

8       加载驱动程序

在加载/卸载模块时可以通过命令$tail –f/var/adm/mssages来查看cmn_err输出的信息。

Ø  加载驱动程序

加载驱动要确保是root用户,使用add_drv命令来加载驱动程序#add_drv dummy。在查看的/var/adm/messages窗口中会看到加载信息。

Ø  显示驱动程序模块信息

可以使用modinfo命令显示驱动的模块信息

Ø  读写设备

可以使用cat 命令来测试,

Ø  卸载驱动程序

确保root用户,使用rem_drv命令。rem drv dummy.

 

数据结构

struct dev_ops  {

         int              devo_rev;         /* Driver build version               */

         int              devo_refcnt;    /* device reference count        */

 

         int              (*devo_getinfo)(dev_info_t *dip,

                                ddi_info_cmd_t infocmd, void *arg, void**result);

         int              (*devo_identify)(dev_info_t *dip);

         int              (*devo_probe)(dev_info_t *dip);

         int              (*devo_attach)(dev_info_t *dip,ddi_attach_cmd_t cmd);

         int              (*devo_detach)(dev_info_t *dip,ddi_detach_cmd_t cmd);

         int              (*devo_reset)(dev_info_t *dip,ddi_reset_cmd_t cmd);

 

         structcb_ops  *devo_cb_ops;         /* cb_ops pointer for leaf drivers   */

         structbus_ops         *devo_bus_ops;       /* bus_ops pointer for nexus drivers */

         int              (*devo_power)(dev_info_t *dip, intcomponent,

                                intlevel);

         int              (*devo_quiesce)(dev_info_t *dip);

};

struct cb_ops  {

         int    (*cb_open)(dev_t *devp, int flag, int otyp,cred_t *credp);

         int    (*cb_close)(dev_t dev, int flag, int otyp,cred_t *credp);

         int    (*cb_strategy)(struct buf *bp);

         int    (*cb_print)(dev_t dev, char *str);

         int    (*cb_dump)(dev_t dev, caddr_t addr, daddr_tblkno, int nblk);

         int    (*cb_read)(dev_t dev, struct uio *uiop,cred_t *credp);

         int    (*cb_write)(dev_t dev, struct uio *uiop,cred_t *credp);

         int    (*cb_ioctl)(dev_t dev, int cmd, intptr_targ, int mode,

                       cred_t *credp, int *rvalp);//可以通过填充此函数来完成用户的配置请求

         int    (*cb_devmap)(dev_t dev, devmap_cookie_t dhp,offset_t off,

                            size_tlen, size_t *maplen, uint_t model);

         int    (*cb_mmap)(dev_t dev, off_t off, int prot);

         int    (*cb_segmap)(dev_t dev, off_t off, struct as*asp,

                       caddr_t *addrp, off_t len, unsigned intprot,

                       unsigned int maxprot, unsigned int flags,cred_t *credp);

         int    (*cb_chpoll)(dev_t dev, short events, intanyyet,

                       short *reventsp, struct pollhead **phpp);

         int    (*cb_prop_op)(dev_t dev, dev_info_t *dip,

                       ddi_prop_op_t prop_op, int mod_flags,

                       char *name, caddr_t valuep, int *length);

 

         structstreamtab *cb_str;       /* streamsinformation */

 

         /*

          * The cb_flag fields are here to tell thesystem a

          * bit about the device. The bit definitionsare

          * in <sys/conf.h>.

          */

         int    cb_flag;             /*driver compatibility flag */

         int    cb_rev;                       /*cb_ops version number */

         int    (*cb_aread)(dev_t dev, struct aio_req *aio,cred_t *credp);

         int    (*cb_awrite)(dev_t dev, struct aio_req *aio,cred_t *credp);

};

实例代码

32位或64位系统区分

The following is an example of the isainfo command executed on an UltraSPARC™

system running the 64-bit operating system:(以下是运行在sun的cpu上的64位系统)

% isainfo -v

64-bit sparcv9 applications

32-bit sparcapplications

When the same command is run on an x86 system runnig the 32–bit Solarisoperating

system(以下是运行在X86架构上的32位系统)

% isainfo -v

32-bit i386applications

When the same command is run on an x86 system running the 64–bit Solarisoperating

system: (以下是运行在X86架构上的64位系统)

% isainfo -v

64-bit amd64applications

32-bit i386 applications

驱动程序创建规则

1、  使用基于驱动程序名的前缀来制定全局变量和函数的唯一变量。

2、  使用cmn_err函数而不是printf来记录驱动程序活动

3、  使用assert来捕捉意外的出错返回。

4、  使用mutex_owned来验证加锁要求和编制相关文档

5、  将单独设备用于每个控制的设备。

6、  驱动程序中尽可能多得使用DDI函数

7、  设备驱动应向只受控于该驱动程序的DMA缓冲区写入数据

8、  需要DMA传输时,使用ddi_umem_alloc函数

9、  所有设备都应支持热插拔和电源管理

10、             将volatie关键字应用于应用了设备寄存器的任何变量

 

参考文献:

SUN-编写设备驱动程序.pdf

SOLARIS设备驱动程序的研究与开发.pdf

Solaris设备驱动教程.chm

solaris 64-bit Guide.pdf

http://download.oracle.com/docs/cd/E24847_01/html/819-7057/loading-1.html#scrolltoc

http://download.oracle.com/docs/cd/E19205-01/820-3035/index.html

http://download.oracle.com/docs/cd/E19205-01/820-3035/gabcd/index.html

http://download.oracle.com/docs/cd/E19205-01/820-3033/gemls/index.html



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
TREX说明书: 命令名称: Z1 简便找盘 XINXI 查看硬盘信息 chkresfall检测固件 smt 查看SMART表 csmt 清SMART表 svmod 0x.. 单个备份模块 wrmod 0x.. 写入备份好的单个模块 pg 合并GP pgn 立即合并pg CGLIST 清G CFILE 0X33 清P Depophd 1,X关头 DM 内部低格 rdfl 2;edit 编辑ID wrdir 写01扇区 GSGJQ 格式化固件区 QLGJQ固件区清零 clribilog 清E0-E6 F0-F1的LOG HEADTEST 自动测试当前所有磁头好坏,好的返回OK,坏的返回BAD。 getPEDATA 自动获取PE bin 读E8 E9 E10 tp 校准指针 sf1 从0x01自动开自校准(范围S53. S58) 处理完后,出现COMPLETELY(完成)此时需要手工断电通电一次,校准即开启。校准时候用 POLL 0 命令实时查看进程。 sf2 从0x0e自动开自校准(若sf失败,则用这个跑(范围S53. S58)) 处理完后,出现COMPLETELY(完成)此时需要手工断电通电一次, 校准即开启。校准时候用POLL 0命令实时查看进程。 stop 强制停校准(盘在IDE 1,不是IDE0) rdTRK 自动备份全固件磁道 (范围S53. S58) wrTRKa 自动写全固件磁道 (范围S53. S58) swap58 自动全换SABRE58系列固件(范围S53. S58) swap53 自动全换SABRE53系列固件(范围S53. S58) wr58 自动全写S58系列固件(范围S53. S58) wr53 自动全写S53系列固件(范围S53. S58) sv58 自动全备份S58系列固件(范围S53. S58) sv53 自动全备份S53系列固件(范围S53. S58) wrdir 写dir wrrplist 写35模块 re47 自动配47适配器模块(范围S53. S58) re40 自动配40适配器模块(范围S53. S58) SVLROM 保存128K ROM WRROML 写128K ROM CLRCOLOR 修护色块和坏道的命令 CLR0 清零 CLRPW 解密 setPWD 加密 disablePWD 禁用密码 unlockUnit SECURITY UNLOCK Macro erasePrep SECURITY ERASE PREPARE Macro eraseUnit SECURITY ERASE UNIT Macro SMARTSTAT SMART归位 smtRdData SMART数据读取 htl L板测磁头 hlr换L板ROM AdpL自适配L板47 KadpL headnum 砍L板所选磁头适配 svtl uhead 保存L板所选磁头磁道 wrtl uhead 写所选磁头磁道 SVALL 存全固件RPM wrall 写全固件RPM svhawk保存HAWK全固件 wrhawk写HAWK全固件 svthawk保存HAWK磁道 wrthawk写HAWK磁道 initall初始化三项 getadpfrom40 从40拷贝MR适配进47 getadpfrom41 从41拷贝MR适配进47 raidergetadpfrom40 raider系列从40拷贝MR适配进47 raidergetadpfrom41 raider系列从41拷贝MR适配进47 svseqfull SEQ保存全固件 wrseqfull SEQ写全固件 SVBUC BUC保存全固件 WRBUC BUC写全固件 SVRAIDER RAIDER保存全固件 WRRAIDER RAIDER写全固件 kill headnum 这几个系列的砍头 adujst40 调整40模块 fmtcover 格式覆盖 SVORION ORION保存全固件 WRORION ORION写全固件 ORIONadp47 ORION配47 ROYL tp32 32位校准指针 ROYSF 自动开ROYL系列校准(从01开始跑,即第一个DC)处理完后,出现COMPLETELY(完成)此时需要手工断电通电一次,校准即开启。 校准时候用POLL 0命令实时查看进程。 STOPROY 强制停ROY校准 ROYHEADTEST ROY测试磁头 ROYRE47 ROY配ROM ROYMAKEROM ROY配ROM BAKpermovl 备份11号ATA模块 新命令: SF、SFP校准 LDR自动加载11 tpseq 设置校准起始指针 Get_adp_info 获取适配信息 Get_adp_new_info 获取适配信息(新) displayheadmap、hdmap 显示磁头映射 AAJSre40 AAJS盘从47拷贝MR到40 AAJSre47 AAJS盘从40拷贝MR到47 adjust_40(微代码,调用时加.)适配40 adjust_47(微代码,调用时加.)适配47 Adpzeus自适配ZEUS系列47 AdpR R系自适配47 K47 umaxhead UHEAD 砍头且设置47 kadpzeus headnum砍ZEUS所选磁头适配 cutmap uhead 关要砍的头的映射 SETPARM uhead设置所需磁头数的TPI和CAP getflash读取ROY备份ROM SA并保存 peirom配ROM svall 存全固件RPM,并存ROM.BIN, 11 PERMOVL.BIN, 35 RPLIST.BIN SVFW 保存全固件 SVBASE 存33 40 41 SVROM 保存192K ROM SV2ROM 保存256K ROM SVROMMOD 保存A 47 SVT UHEAD 保存所选磁头磁道 SVMOD OverlayNum 保存单个模块 WRBASE 写33 40 41 WRROMMOD 写A 47 WRROM 写192K ROM WR2ROM 写256K ROM WRALL 全写固件RPM RWRFW 自读自写全固件RPM wrFW 全写固件RPM WRT UHEAD 写入所选磁头磁道 WRTL UHEAD 写入所选磁头磁道 WrMOD BinFileNum 写入单个模块 SETHQ ULCAP设置HQ自定义CAP SETTAG ULCAP设置TAG自定义CAP scap显示CAP STPI显示TPI dpst、dpst1显示流程 EMDL编辑磁盘型号 HT测试头 HDT UHEAD测试所选头 SETLBA ULBA设置自定义LBA setdcm udcm设置自定义DCM setTPI为全部磁头设置TPI setCap为全部磁头设置CAP ST0 UTPI为0头设置TPI ST1 UTPI为1头设置TPI ST2 UTPI为2头设置TPI ST3 UTPI为3头设置TPI ST4 UTPI为4头设置TPI ST5 UTPI为5头设置TPI ST6 UTPI为6头设置TPI ST7 UTPI为7头设置TPI SC0 UCAP为0头设置CAP SC1 UCAP为1头设置CAP SC2 UCAP为2头设置CAP SC3 UCAP为3头设置CAP SC4 UCAP为4头设置CAP SC5 UCAP为5头设置CAP SC6 UCAP为6头设置CAP SC7 UCAP为7头设置CAP RADP读103并重新适配47 REPAIR重建DIR SFLOG查校准LOG CM对比47和103 ClrRES prmFileID、ClrR prmFileID、Clrbinfile binfile清空所选模块 CLEARFILE UFILEID清空所选ID模块 CLRPSTLOG清除SPTLOG CLRLIST清除所有缺陷表 kadp3 headnum、kadp2 headnum、kNEW2ROM headnum、knew3 headnum砍所选磁头适配 k0 headnum、k1 headnum、k3 headnum砍头 vp1、vp显示P表 VG显示G表 c4改28走C4 FmtR格式化固件区 cf清空缺陷 sz显示ZONE kz uznum ulba砍所选段位LBA SHOWZONE显示ZONE kZONE uzone砍所选段位 hr换ROM gb搞0B模块 h40换40 固件区 允许输入拉丁字符的拼音 Firmware District 常用指令 1、 关头 Depophd 1,X 2、 配47 Re47 3、 格式化 Fmtunit 4、 启动自校 Sf 5、 备份固件 Sv53,sv58 6、 写全部固件 Wr53,wr58 7、 自动更换替换固件 Swap53,swap58 8、 写01扇区 wrdir 9、 格式化固件区 fmtrsvd 10、 固件区清零 zrcyls 11、 清LOG clribilog sv109t wr109t wr083j sv083j sv218b wr218b adp0 adp1
说明书: 命令名称: dut1 简便找盘 idp或info 查看硬盘信息 chkresfall 检测固件 RDIRSECT 显示硬盘固件目录 smart 查看SMART表 clrsmart 清SMART表 svmod 0x.. 单个备份模块 wrmod 0x.. 写入备份好的单个模块 remergepg 合并GP remergepgnow 立即合并pg CLRGLIST 清G CLRFILE 0X33 清P Depophd 1,X 关头 Fmtunit 内部低格 rdfl 2;edit 编辑ID wrldir 写01扇区 fmtrsvd 格式化固件区 zrcyls 固件区清零 clribilog 清E0-E6 F0-F1的LOG HEADTEST 自动测试当前所有磁头好坏,好的返回OK,坏的返回BAD。 getPEDATA 自动获取PE bin 读E8 E9 E10 tp 校准指针 sf1 从0x01自动开自校准(范围S53. S58) 处理完后,出现COMPLETELY(完成)此时需要手工断电通电一次,校准即开启。校准时候用 POLL 0 命令实时查看进程。 sf2 从0x0e自动开自校准(若sf失败,则用这个跑(范围S53. S58)) 处理完后,出现COMPLETELY(完成)此时需要手工断电通电一次,校准即开启。校准时候用POLL 0命令实时查看进程。 stop 强制停校准(盘在IDE 1,不是IDE0) rdTRK 自动备份全固件磁道 (范围S53. S58) wrTRKa 自动写全固件磁道 (范围S53. S58) swap58 自动全换SABRE58系列固件(范围S53. S58) swap53 自动全换SABRE53系列固件(范围S53. S58) wr58 自动全写S58系列固件(范围S53. S58) wr53 自动全写S53系列固件(范围S53. S58) sv58 自动全备份S58系列固件(范围S53. S58) sv53 自动全备份S53系列固件(范围S53. S58) wrdir 写dir wrrplist 写35模块 re47 自动配47适配器模块(范围S53. S58) re40 自动配40适配器模块(范围S53. S58) SVLROM 保存128K ROM WRROML 写128K ROM CLRCOLOR 修护色块和坏道的命令 CLR0 清零 CLRPW 解密 setPWD 加密 disablePWD 禁用密码 unlockUnit SECURITY UNLOCK Macro erasePrep SECURITY ERASE PREPARE Macro eraseUnit SECURITY ERASE UNIT Macro SMARTSTAT SMART归位 smtRdData SMART数据读取 htl L板测磁头 hlr换L板ROM AdpL自适配L板47 KadpL headnum 砍L板所选磁头适配 svtl uhead 保存L板所选磁头磁道 wrtl uhead 写所选磁头磁道 SVALL 存全固件RPM wrall 写全固件RPM svhawk保存HAWK全固件 wrhawk写HAWK全固件 svthawk保存HAWK磁道 wrthawk写HAWK磁道 initall初始化三项 getadpfrom40 从40拷贝MR适配进47 getadpfrom41 从41拷贝MR适配进47 raidergetadpfrom40 raider系列从40拷贝MR适配进47 raidergetadpfrom41 raider系列从41拷贝MR适配进47 svseqfull SEQ保存全固件 wrseqfull SEQ写全固件 SVBUC BUC保存全固件 WRBUC BUC写全固件 SVRAIDER RAIDER保存全固件 WRRAIDER RAIDER写全固件 kill headnum 这几个系列的砍头 adujst40 调整40模块 fmtcover 格式覆盖 SVORION ORION保存全固件 WRORION ORION写全固件 ORIONadp47 ORION配47 ROYL tp32 32位校准指针 ROYSF 自动开ROYL系列校准(从01开始跑,即第一个DC)处理完后,出现COMPLETELY(完成)此时需要手工断电通电一次,校准即开启。校准时候用POLL 0命令实时查看进程。 STOPROY 强制停ROY校准 ROYHEADTEST ROY测试磁头 ROYRE47 ROY配ROM ROYMAKEROM ROY配ROM BAKpermovl 备份11号ATA模块 新命令: SF、SFP校准 LDR自动加载11 tpseq 设置校准起始指针 Get_adp_info 获取适配信息 Get_adp_new_info 获取适配信息(新) displayheadmap、hdmap 显示磁头映射 AAJSre40 AAJS盘从47拷贝MR到40 AAJSre47 AAJS盘从40拷贝MR到47 adjust_40(微代码,调用时加.)适配40 adjust_47(微代码,调用时加.)适配47 Adpzeus自适配ZEUS系列47 AdpR R系自适配47 K47 umaxhead UHEAD 砍头且设置47 kadpzeus headnum砍ZEUS所选磁头适配 cutmap uhead 关要砍的头的映射 SETPARM uhead设置所需磁头数的TPI和CAP getflash读取ROY备份ROM SA并保存 peirom配ROM svall 存全固件RPM,并存ROM.BIN, 11 PERMOVL.BIN, 35 RPLIST.BIN SVFW 保存全固件 SVBASE 存33 40 41 SVROM 保存192K ROM SV2ROM 保存256K ROM SVROMMOD 保存A 47 SVT UHEAD 保存所选磁头磁道 SVMOD OverlayNum 保存单个模块 WRBASE 写33 40 41 WRROMMOD 写A 47 WRROM 写192K ROM WR2ROM 写256K ROM WRALL 全写固件RPM RWRFW 自读自写全固件RPM wrFW 全写固件RPM WRT UHEAD 写入所选磁头磁道 WRTL UHEAD 写入所选磁头磁道 WrMOD BinFileNum 写入单个模块 SETHQ ULCAP设置HQ自定义CAP SETTAG ULCAP设置TAG自定义CAP scap显示CAP STPI显示TPI dpst、dpst1显示流程 EMDL编辑磁盘型号 ENTERSN编辑磁盘SN号 HT测试头 HDT UHEAD测试所选头 SETLBA ULBA设置自定义LBA setdcm udcm设置自定义DCM setTPI为全部磁头设置TPI setCap为全部磁头设置CAP ST0 UTPI为0头设置TPI ST1 UTPI为1头设置TPI ST2 UTPI为2头设置TPI ST3 UTPI为3头设置TPI ST4 UTPI为4头设置TPI ST5 UTPI为5头设置TPI ST6 UTPI为6头设置TPI ST7 UTPI为7头设置TPI SC0 UCAP为0头设置CAP SC1 UCAP为1头设置CAP SC2 UCAP为2头设置CAP SC3 UCAP为3头设置CAP SC4 UCAP为4头设置CAP SC5 UCAP为5头设置CAP SC6 UCAP为6头设置CAP SC7 UCAP为7头设置CAP RADP读103并重新适配47 REPAIR重建DIR SFLOG查校准LOG CM对比47和103 ClrRES prmFileID、ClrR prmFileID、Clrbinfile binfile清空所选模块 CLEARFILE UFILEID清空所选ID模块 CLRPSTLOG清除SPTLOG CLRLIST清除所有缺陷表 kadp3 headnum、kadp2 headnum、kNEW2ROM headnum、knew3 headnum砍所选磁头适配 k0 headnum、k1 headnum、k3 headnum砍头 vp1、vp显示P表 VG显示G表 c4改28走C4 FmtR格式化固件区 cf清空缺陷 sz显示ZONE kz uznum ulba砍所选段位LBA SHOWZONE显示ZONE kZONE uzone砍所选段位 hr换ROM gb搞0B模块 h40换40
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值