打印

移植FATFS到S3C2440的SD卡上遇到的困难,请高手指点

[复制链接]
15845|60
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dsoyy|  楼主 | 2010-4-7 13:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
移植FATFS到S3C2440的SD卡上遇到的困难,其中有几个底层函数需要改写:
disk_initialize - Initialize disk drive
disk_status - Get disk status
disk_read - Read sector(s)
disk_write - Write sector(s)
disk_ioctl - Control device dependent features
get_fattime - Get current time

目前在disk_read 函数遇到困难,这个函数是读取N个扇区的函数,不知道如何去实现,请做过的朋友的指教!

相关帖子

沙发
dsoyy|  楼主 | 2010-4-7 13:27 | 只看该作者
我按照网上的“比较详细介绍FatFs文件系统移植的**”(http://hi.baidu.com/wu_yuzhi/blog/item/50ce54a9247d4cb8ca130c3f.html)的操作步骤来实现。
到底层函数
Read Sector(s)                                                        

DRESULT disk_read (
        BYTE drv,                /* Physical drive nmuber (0..) */
        BYTE *buff,                /* Data buffer to store read data */
        DWORD sector,        /* Sector address (LBA) */
        BYTE count                /* Number of sectors to read (1..255) */
)
{
        DRESULT res;
        int result;

        switch (drv) {
        case ATA :
                result = ATA_disk_read(buff, sector, count);
                // translate the reslut code here

                return res;
/*
        case MMC :
                result = MMC_disk_read(buff, sector, count);
                // translate the reslut code here

                return res;

        case USB :
                result = USB_disk_read(buff, sector, count);
                // translate the reslut code here
*/
                return res;
        }
        return RES_PARERR;
}
因为我只有一个驱动盘SD卡,所以我主要完成这个函数ATA_disk_read(buff, sector, count);
而这个函数不在FATFS既知函数范围内就是读取多个扇区的函数,不知道如何去实现

使用特权

评论回复
板凳
tennis_01| | 2010-4-7 13:29 | 只看该作者
OH MY GOD!第一次上来,偶还是个新手,居然坐到了沙发,先赞一个!!

使用特权

评论回复
地板
liuwei0908| | 2010-4-7 13:34 | 只看该作者
:L,这里不缺沙发

使用特权

评论回复
5
dsoyy|  楼主 | 2010-4-7 17:12 | 只看该作者
本帖最后由 dsoyy 于 2010-4-7 17:13 编辑

我用的是飞凌的开发板OK2440-III,SD卡底层有如下API函数:
void Rd_Block(void)
{
    U32 mode;
    int status;

    rd_cnt=0;   
    Uart_Printf("Block read test[ Polling read ]\n");
     mode = 0 ;

//    rSDICON = rSDICON|(1<<1);        // FIFO reset
        rSDIFSTA=rSDIFSTA|(1<<16);        // FIFO reset

    if(mode!=2)
        rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)|(2<<12)|(block<<0);        //YH 040220
                //Word Rx, Rx after cmd, blk, 4bit bus, Rx start, blk num, data start, data transmit mode

    rSDICARG=0x0;        // CMD17/18(addr)

RERDCMD:
    switch(mode)
    {
        case POL:
            if(block<2)        // SINGLE_READ
            {
                rSDICCON=(0x1<<9)|(0x1<<8)|0x51;    // sht_resp, wait_resp, dat, start, CMD17
                if(!Chk_CMDend(17, 1))        //-- Check end of CMD17
                    goto RERDCMD;            
            }
            else        // MULTI_READ
            {
                rSDICCON=(0x1<<9)|(0x1<<8)|0x52;    // sht_resp, wait_resp, dat, start, CMD18
                if(!Chk_CMDend(18, 1))        //-- Check end of CMD18
                    goto RERDCMD;
            }

            rSDICSTA=0xa00;        // Clear cmd_end(with rsp)            

            while(rd_cnt<128*block)        // 512*block bytes
            {
                if((rSDIDSTA&0x20)==0x20) // Check timeout
                {
                    rSDIDSTA=(0x1<<0x5);  // Clear timeout flag
                    break;
                }
                status=rSDIFSTA;
                if((status&0x1000)==0x1000)        // Is Rx data?
                {
                    *Rx_buffer++=rSDIDAT;
                    rd_cnt++;
                }
            }
            break;
        
        case INT:
            pISR_SDI=(unsigned)Rd_Int;
            rINTMSK = ~(BIT_SDI);
            
            rSDIIMSK=5;        // Last & Rx FIFO half int.

            if(block<2)        // SINGLE_READ
            {
                rSDICCON=(0x1<<9)|(0x1<<8)|0x51;    // sht_resp, wait_resp, dat, start, CMD17
                if(!Chk_CMDend(17, 1))        //-- Check end of CMD17
                    goto RERDCMD;            
            }
            else        // MULTI_READ
            {
                rSDICCON=(0x1<<9)|(0x1<<8)|0x52;    // sht_resp, wait_resp, dat, start, CMD18
                if(!Chk_CMDend(18, 1))        //-- Check end of CMD18
                    goto RERDCMD;
            }
   
            rSDICSTA=0xa00;        // Clear cmd_end(with rsp)

            while(rd_cnt<128*block);

            rINTMSK |= (BIT_SDI);
            rSDIIMSK=0;        // All mask
            break;

        case DMA:
            pISR_DMA0=(unsigned)DMA_end;
            rINTMSK = ~(BIT_DMA0);
                rSDIDCON=rSDIDCON|(1<<24); //YH 040227, Burst4 Enable

            rDISRC0=(int)(SDIDAT);        // SDIDAT
            rDISRCC0=(1<<1)+(1<<0);        // APB, fix
            rDIDST0=(U32)(Rx_buffer);        // Rx_buffer
            rDIDSTC0=(0<<1)+(0<<0);        // AHB, inc
            rDCON0=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;
            //handshake, sync PCLK, TC int, single tx, single service, SDI, H/W request,
            //auto-reload off, word, 128blk*num
            rDMASKTRIG0=(0<<2)+(1<<1)+0;    //no-stop, DMA2 channel on, no-sw trigger

//            rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<15)|(2<<12)|(block<<0);
            rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<15)|(1<<14)|(2<<12)|(block<<0);
                    // Word Rx, Rx after rsp, blk, 4bit bus, dma enable, Rx start, blk num, Data start, data receive mode, YH 040220
            if(block<2)        // SINGLE_READ
            {
                rSDICCON=(0x1<<9)|(0x1<<8)|0x51;    // sht_resp, wait_resp, dat, start, CMD17
                if(!Chk_CMDend(17, 1))        //-- Check end of CMD17
                    goto RERDCMD;            
            }
            else        // MULTI_READ
            {
                rSDICCON=(0x1<<9)|(0x1<<8)|0x52;    // sht_resp, wait_resp, dat, start, CMD18
                if(!Chk_CMDend(18, 1))        //-- Check end of CMD18
                    goto RERDCMD;
            }

            rSDICSTA=0xa00;        // Clear cmd_end(with rsp)
            while(!TR_end);
                //Uart_Printf("rSDIFSTA=0x%x\n",rSDIFSTA);
            rINTMSK |= (BIT_DMA0);
            TR_end=0;
            rDMASKTRIG0=(1<<2);        //DMA0 stop
            break;

        default:
            break;
    }
    //-- Check end of DATA
    if(!Chk_DATend())
        Uart_Printf("dat error\n");

        rSDIDCON=rSDIDCON&~(7<<12);                //YH 040220, Clear Data Transfer mode => no operation, Cleata Data Transfer start
        rSDIFSTA=rSDIFSTA&0x200;        //Clear Rx FIFO Last data Ready, YH 040221
    rSDIDSTA=0x10;        // Clear data Tx/Rx end detect

    if(block>1)
    {
RERCMD12:   
        //--Stop cmd(CMD12)
        rSDICARG=0x0;            //CMD12(stuff bit)
        rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;//sht_resp, wait_resp, start, CMD12

        //-- Check end of CMD12
        if(!Chk_CMDend(12, 1))
            goto RERCMD12;
        rSDICSTA=0xa00;        // Clear cmd_end(with rsp)
    }
}

使用特权

评论回复
6
dsoyy|  楼主 | 2010-4-7 17:17 | 只看该作者
本帖最后由 dsoyy 于 2010-4-7 17:20 编辑

函数很长,但为了说明问题还是发上来。

我采用的是DMA方式读取SD卡位图文件送到TFT。
我底层函数里面需要补充的函数就是ATA_disk_read(buff, sector, count);
而这个函数就是我上面发的Rd_Block,这样理解对吧
我要做的就是要改写Rd_Block,使其包含接收读到数据的buff,起始扇区和扇区数目,对吧

diskio.rar

1.28 KB

sdi.rar

6.29 KB

使用特权

评论回复
7
dsoyy|  楼主 | 2010-4-7 17:54 | 只看该作者
从函数可以看出,如果我采用的是DMA,那么变量值switch(mode)的参数就是DMA的宏数值。

rDIDST0=(U32)(Rx_buffer);        // Rx_buffer
由此可以推断出接收数据的buff就是Rx_buffer
这个应该对应ATA_disk_read(buff, sector, count);里面的第1个参数


rSDICARG=0x0;和 rSDICARG=0x0;        // CMD17/18(addr)
可以推断出rSDICARG和我读取数据所在扇区的地址有关系,具体什么关系不得而知了,这个应该对应ATA_disk_read(buff, sector, count);里面的第二个参数

使用特权

评论回复
8
liuwei0908| | 2010-4-7 21:05 | 只看该作者
本帖最后由 liuwei0908 于 2010-4-7 21:06 编辑

基于S3C2440的SD卡读写驱动程序(支持多块读写操作):

/*===============================================================================================*/

static        int        SD_ReadSector(U32 sector,U8 *buf,U32 count)        
{
  
        U32                 status;  
        register        data,rd_cnt;
               
        ////        

        if(count==0)        return 0;
        rSDIFSTA|=(1<<16);        // FIFO reset
        rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)|(2<<12)|(count<<0);        //YH 040220
        //Word Rx, Rx after cmd, blk, 4bit bus, Rx start, blk num, data start, data transmit mode
        
        ///////
               
        if(count>1)        
        {
                // MULTI_READ
                Send_CMD(CMD18,sector<<9,1,0);   
        }
        else        
        {
                // SINGLE_READ
                Send_CMD(CMD17,sector<<9,1,0);
        }
        
               
        ////
        rd_cnt        =0;

        while(rd_cnt<(128*count))        // 512*block bytes
        {
                    
                status=rSDIFSTA;        
                        
                if(status&(1<<12))        //Rx FIFO Ready
                {
                           
                        data=rSDIDAT;
                          
                        *buf++=data;
                        *buf++=(data>>8);
                        *buf++=(data>>16);
                        *buf++=(data>>24);
                        
                        rd_cnt++;
                }
                        
        }
        
        if(!WaitDatEnd())
        {
                DebugPrintf("rd error\n");
        }
        
        if(count>1)
        {
                Send_CMD(CMD12,0,1,0);
        }
        
        return 1;
        
}

/*===============================================================================================*/

static        int        SD_WriteSector(U32 sector,U8 *buf,U32 count)        
{

           
            int status,i;
                U32        wt_cnt,data;
                ////
                  
                  
                   if(count==0)        return 0;
           
           
                   WaitDatReady();
                  
                rSDIFSTA|=(1<<16);        //YH 040223 FIFO reset
                rSDIDCON=(2<<22)|(1<<20)|(1<<17)|(Wide<<16)|(1<<14)|(3<<12)|(count<<0);        //YH 040220
                            // Tx after rsp, blk, 4bit bus, Tx start, blk num

                ///////
                //DebugPrintf("sd_wt -> %08XH - %d\n",sector,count);
               
                if(count>1)        
                {
                        // MULTI_WRITE
                        
                        Send_CMD(CMD55,RCA<<16,1,0);        //ACMD23
                        Send_CMD(CMD23,count,1,0);        
                        
                        Send_CMD(CMD25,sector<<9,1,0);   
                }
                else        
                {
                        // SINGLE_WRITE
                        Send_CMD(CMD24,sector<<9,1,0);
                }

        
               
            wt_cnt        =0;
              
            while(wt_cnt<128*count)
            {
                        status=rSDIFSTA;
                        
                        if(status&(1<<13)) //Tx FIFO Ready
                        {        
                                data        =*buf++;
                                data        |=(*buf++)<<8;
                                data        |=(*buf++)<<16;
                                data        |=(*buf++)<<24;
                                   rSDIDAT        =data;
                           
                            wt_cnt++;
                        }
            }
            
               
            //-- Check end of DATA
            if(!WaitDatEnd())
            {
                        DebugPrintf("dat err\n");
                }
               
               
                if(count>1)
                {
                        Send_CMD(CMD12,0,1,0);
                }
             return 1;

}

/*===============================================================================================*/

使用特权

评论回复
9
dsoyy|  楼主 | 2010-4-7 22:10 | 只看该作者
感谢8楼。

有一个函数请您给指点下源码:
Send_CMD(CMD18,sector<<9,1,0);   
我的工程里面没有这个函数,还有宏。这个宏好像在SPI指令里面有。

使用特权

评论回复
10
liuwei0908| | 2010-4-7 23:03 | 只看该作者
我使用的是 SDI总线,不是SPI

使用特权

评论回复
11
liuwei0908| | 2010-4-7 23:05 | 只看该作者
基于S3C2440 SDI的SendCMD源码:

static        int        Send_CMD(U8 cmd,U32 arg,int resp,void *buf)
{
       
        rSDICARG=arg;       
       
        switch(resp)
        {
                case        0:        //No Response
                rSDICCON=(0<<10)|(0<<9)|(1<<8)|(cmd);       
                break;
                ////
               
                case        1:        //Short Response
                rSDICCON=(0<<10)|(1<<9)|(1<<8)|(cmd);       
                break;
                ////
               
                default:        //Long Response
                rSDICCON=(1<<10)|(1<<9)|(1<<8)|(cmd);
                break;
        }
       
        ////
       
       
        return WaitCmdEnd(cmd,resp,buf);
       
   
}

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
dsoyy + 1
12
dsoyy|  楼主 | 2010-4-8 10:41 | 只看该作者
有几个函数我没有,所以如下面的方法来实现:
1、写扇区的函数 SD_WriteSector(U32 sector,U8 *buf,U32 count)     中的WaitDatReady();我屏蔽处理。
2、Send_CMD(U8 cmd,U32 arg,int resp,void *buf)函数的返回值我用如下函数代替:
int Chk_CMDend(int cmd, int be_resp)
//0: Timeout
{
    int finish0;

    if(!be_resp)    // No response
    {
            finish0=rSDICSTA;
                while((finish0&0x800)!=0x800)        // Check cmd end
            finish0=rSDICSTA;

        rSDICSTA=finish0;// Clear cmd end state

        return 1;
    }
    else        // With response
    {
            finish0=rSDICSTA;
        while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x400) ))    // Check cmd/rsp end
                finish0=rSDICSTA;

        if(cmd==1 | cmd==41)        // CRC no check, CMD9 is a long Resp. command.

        {
            if( (finish0&0xf00) != 0xa00 )  // Check error
            {
                rSDICSTA=finish0;   // Clear error state

                if(((finish0&0x400)==0x400))
                    return 0;        // Timeout error
                }
            rSDICSTA=finish0;        // Clear cmd & rsp end state
        }
        else        // CRC check
        {
            if( (finish0&0x1f00) != 0xa00 )        // Check error
            {
                Uart_Printf("CMD%d:rSDICSTA=0x%x, rSDIRSP0=0x%x\n",cmd, rSDICSTA, rSDIRSP0);
                rSDICSTA=finish0;   // Clear error state

                if(((finish0&0x400)==0x400))
                    return 0;        // Timeout error
                }
            rSDICSTA=finish0;
        }
        return 1;
    }
}

使用特权

评论回复
13
dsoyy|  楼主 | 2010-4-8 10:46 | 只看该作者
此外还有几个疑问要请教高手:
这个移植是否成功的方法判断,因为目前只用DMA来实现所以不经过内存的过程,无法通过读取一个文件并单步跟踪来查看。 所以我想到的最简单的方法是把DMA的目的地址配置成TFT缓存,读到的文件内容直接送过去显示,初次使用DMA还请您多指教

使用特权

评论回复
14
liuwei0908| | 2010-4-8 11:29 | 只看该作者
单任务环境下DMA使用非常简单:
只要设置好DMA的Dst,Src,Count,再启动DMA就行了.
在DMA Done中断中,清理一下相关的标记.

如果是多任务系统,得考虑一下资源抢占的问题

使用特权

评论回复
15
dsoyy|  楼主 | 2010-4-8 13:23 | 只看该作者
我现在在SD卡里米建立一个TXT,操作如下:
disk_initialize(0);//初始化SD卡
res = f_open(&file, "data.txt", FA_OPEN_EXISTING | FA_READ);
执行后发现SD卡内还是空空的,感觉缺少一个FATFS的初始化,但是没有找到这个初始化。谁知道这样操作错在哪里?

使用特权

评论回复
16
liuwei0908| | 2010-4-8 14:51 | 只看该作者
先要挂接一个disk才行

使用特权

评论回复
17
dsoyy|  楼主 | 2010-4-8 15:57 | 只看该作者
disk_initialize(0);//初始化SD卡
Write_SD("a.txt","12345",2);

void Write_SD(const char *write_file,const void *buffer,UINT count)
{
  FATFS fs;
  FIL fil;
  U32 bw;
  FRESULT res;                //文件系统返回信息

   f_mount(0,&fs);//注册一个文件系统
   res=f_open(&fil,write_file,FA_OPEN_ALWAYS|FA_WRITE);//建立文件的文件名最长8个字节
/*   if(res!=FR_OK)
   {
        Uart_Printf("文件不能写!!!\r\n");
        return;
    }
     
        res=f_lseek(&fil,fil.fsize);
        res=f_write(&fil,buffer,count,&bw);
*/
    f_close(&fil);
        f_mount(0, NULL);
}

但是只要调用f_open()就会在超级终端出现如下错误:CMD55:rSDICSTA=0xc06, rSDIRSP0=0x920
CMD55:rSDICSTA=0xc06, rSDIRSP0=0x920
CMD55:rSDICSTA=0xc06, rSDIRSP0=0x920
CMD55:rSDICSTA=0xc06, rSDIRSP0=0x920
CMD55:rSDICSTA=0xc06, rSDIRSP0=0x920
CMD55:rSDICSTA=0xc06, rSDIRSP0=0x920
CMD55:rSDICSTA=0xc06, rSDIRSP0=0x920
Initialize fail
No Card assertion
CMD88:rSDICSTA=0xc06, rSDIRSP0=0x920

使用特权

评论回复
18
liuwei0908| | 2010-4-8 16:19 | 只看该作者
SD卡初始化失败

使用特权

评论回复
19
dsoyy|  楼主 | 2010-4-8 16:26 | 只看该作者
如果不调用这个f_open函数是没有问题的,给我的感觉执行f_open的时候又对SD卡初始化了一次

使用特权

评论回复
20
xfcjava2| | 2010-4-8 20:19 | 只看该作者
我提供给你的程序是我已经用在工程中的,请参考!

DRESULT disk_read (
        BYTE drv,                /* Physical drive nmuber (0..) */
        BYTE *buff,                /* Data buffer to store read data */
        DWORD sector,        /* Sector address (LBA) */
        BYTE count                /* Number of sectors to read (1..255) */
)
{                
        int result;

        switch (drv) {
        case ATA :
         result = ATA_disk_read(buff, sector, count); 

                return RES_OK;

        case MMC :
         result = MMC_disk_read(buff, sector, count);  

                return RES_OK;

        case USB :
         result = USB_disk_read(buff, sector, count);  

                return result;
        }
        return RES_PARERR;
}


/*********************************************************************************************************
** 函数名称: MMC_disk_read
** 功能描述:
** 输   入: buff  :Data buffer to store read data
**           sector:Sector address (LBA)
**           count:Number of sectors to read (1..255)
** 输   出: TRUE,正常返回
**                         FALSE,出错返回
********************************************************************************************************/

int  MMC_disk_read (BYTE *buff,        DWORD sector,BYTE count        )
{

   sector *= 512;        /* Convert to byte address if needed */
   
    if (count == 1) /* Single block read */
    {       
        s3c2440_Printf("SD Single block read--->\n");
        
                if(rcvr_datablock(buff, 512))/* READ_SINGLE_BLOCK */                       
                        count = 0;
        }
        else /* Multiple block read */
        {       
            s3c2440_Printf("SD Multiple block read--->\n");  
                                   
            if(rcvr_datablock(buff, count*512))/* READ_SINGLE_BLOCK */                       
                        count = 0;
        }
   
   return count ? RES_ERROR : RES_OK;
}


static  BOOL rcvr_datablock (BYTE *buff,UINT btr)
{   
    //Polling read Mode
   
    int status;
   
    unsigned int rcv_num=0;
   
    UINT blk_num;
   
    DWORD rcv_tmp;   
     
   
    blk_num=btr/512;
   
        rSDIFSTA=rSDIFSTA|(1<<16);        // FIFO reset
   
        rSDIDCON=(2<<22)|(1<<19)|(1<<17)|(Wide<<16)|(1<<14)|(2<<12)|(blk_num<<0);        //YH 040220
                //Word Rx, Rx after cmd, blk, 1bit bus, Rx start, blk num, data start, data transmit mode

    rSDICARG=0x0;        // CMD17/18(addr)

RERDCMD:         

   if(blk_num<2) // SINGLE_READ
    {   
          
           rSDICCON=(0x1<<9)|(0x1<<8)|0x51;    // sht_resp, wait_resp, dat, start, CMD17
           if(!Chk_CMDend(17, 1))        //-- Check end of CMD17
                 goto RERDCMD;                  
    }
   
   else        // MULTI_READ
        {
                rSDICCON=(0x1<<9)|(0x1<<8)|0x52;    // sht_resp, wait_resp, dat, start, CMD18
                if(!Chk_CMDend(18, 1))        //-- Check end of CMD18
                    goto RERDCMD;
        }

rSDICSTA=0xa00;        // Clear cmd_end(with rsp) 

    while(rcv_num<128*blk_num)        // 512=128*4 bytes
    {
                if((rSDIDSTA&0x20)==0x20) // Check timeout
                {
                    rSDIDSTA=(0x1<<0x5);  // Clear timeout flag
                    break;
                }
               
                status=rSDIFSTA;
               
                if((status&0x1000)==0x1000)        // Is Rx data?
                {
                    rcv_tmp=rSDIDAT;
                    
                    *(BYTE*)(buff++)=(BYTE)(rcv_tmp);
                    *(BYTE*)(buff++)=(BYTE)((WORD)(rcv_tmp)>>8);
                    *(BYTE*)(buff++)=(BYTE)((DWORD)(rcv_tmp)>>16);
                    *(BYTE*)(buff++)=(BYTE)((DWORD)(rcv_tmp)>>24);
                    
                    
                    rcv_num++;
                }
    }


   
   
    if(!Chk_DATend())
            return FALSE;
            
        rSDIDCON=rSDIDCON&~(7<<12);                //YH 040220, Clear Data Transfer mode => no operation, Cleata Data Transfer start
        rSDIFSTA=rSDIFSTA&0x200;        //Clear Rx FIFO Last data Ready, YH 040221
    rSDIDSTA=0x10;        // Clear data Tx/Rx end detect
   
   if(blk_num>1)
    {
          RERCMD12:   
                //--Stop cmd(CMD12)
                rSDICARG=0x0;            //CMD12(stuff bit)
                rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;//sht_resp, wait_resp, start, CMD12

                //-- Check end of CMD12
                if(!Chk_CMDend(12, 1))
                    goto RERCMD12;
                rSDICSTA=0xa00;        // Clear cmd_end(with rsp)
    }
   
    return TRUE;                                        /* Return with success */          

}




}

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
dsoyy + 1
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

144

主题

566

帖子

3

粉丝