linux lcd设备驱动剖析二

来源:互联网 发布:邯郸市网络教研 编辑:程序博客网 时间:2024/05/21 11:32

上一节中,分析了s3c2410fb,c的入口出口函数,以及一些重要结构体的分析,初步知道了这是一个平台驱动的架构。

上一节讲到probe函数就没继续往下深究了,这一节里,我们来详细分析s3c24xxfb_probe函数,整体分析如下:

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static int __init s3c24xxfb_probe(struct platform_device *pdev,  
  2.                   enum s3c_drv_type drv_type)  
  3. {  
  4.     struct s3c2410fb_info *info;  
  5.     struct s3c2410fb_display *display;  
  6.     struct fb_info *fbinfo;  
  7.     struct s3c2410fb_mach_info *mach_info;  /* 包含s3c2410fb_display */  
  8.     struct resource *res;  
  9.     int ret;  
  10.     int irq;  
  11.     int i;  
  12.     int size;  
  13.     u32 lcdcon1;  
  14.   
  15.     /*  s3c24xx_fb_set_platdata()里会设置platform_data 
  16.      *  tq2440_machine_init()函数调用s3c24xx_fb_set_platdata(&tq2440_fb_info); 
  17.      *  所以这里传入来的platform_data就是tq2440_fb_info结构体实例 
  18.      */  
  19.     mach_info = pdev->dev.platform_data;  
  20.   
  21.     /* 执行完上面的语句后mach_info指向tq2440_fb_info结构体,而不为NULL  */  
  22.     if (mach_info == NULL) {  
  23.         dev_err(&pdev->dev,  
  24.             "no platform data for lcd, cannot attach\n");  
  25.         return -EINVAL;     /* 表示无效的参数 */  
  26.     }  
  27.   
  28.     /* tq2440_fb_info设置了default_display = 0,num_displays = 1,故这句不会执行 */  
  29.     if (mach_info->default_display >= mach_info->num_displays) {  
  30.         dev_err(&pdev->dev, "default is %d but only %d displays\n",  
  31.             mach_info->default_display, mach_info->num_displays);  
  32.         return -EINVAL;  
  33.     }  
  34.   
  35.     /* display指向tq2440_lcd_cfg,关于LCD屏相关参数的设置 */  
  36.     display = mach_info->displays + mach_info->default_display;  
  37.   
  38.     /* 通过平台设备platform_device获得IRQ 
  39.      * platform_get_irq其实是调用platform_get_resource(dev, IORESOURCE_IRQ, num) 
  40.      */  
  41.     irq = platform_get_irq(pdev, 0);  
  42.     if (irq < 0) {  
  43.         dev_err(&pdev->dev, "no irq for device\n");  
  44.         return -ENOENT;  
  45.     }  
  46.   
  47.     /*  分配一个fb_info结构体,第一参数不为0表示,额外多申请的空间 
  48.      *  用来存放额外的数据,这里用来存放s3c2410fb_info额外的数据 
  49.      *  比如:clk,resource,io,irq_base,drv_type等额外信息 
  50.      */  
  51.     fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);  
  52.     if (!fbinfo)  
  53.         return -ENOMEM;     /* 返回NULL表示失败 */  
  54.   
  55.     /* 相当于pdev->dev->driver_data = fbinfo */  
  56.     platform_set_drvdata(pdev, fbinfo);  
  57.   
  58.     /* 在framebuffer_alloc函数里info->par指向了额外多申请内存空间的首地址 */  
  59.     info = fbinfo->par;          /* 将私有数据赋给info指针变量 */  
  60.     info->dev = &pdev->dev;       /* 指定struct s3c2410fb_info中dev为平台设备中的dev */  
  61.     info->drv_type = drv_type;   /* 驱动类型, DRV_S3C2410还是DRV_S3C2412 */  
  62.   
  63.     /*  通过平台设备platform_device获得资源(IO) */  
  64.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  65.     if (res == NULL) {  
  66.         dev_err(&pdev->dev, "failed to get memory registers\n");  
  67.         ret = -ENXIO;  
  68.         goto dealloc_fb;  
  69.     }  
  70.   
  71.     size = (res->end - res->start) + 1;       /* 资源的大小 */  
  72.   
  73.     /* 申请以res->start地址开始大小为size的I/O内存 */  
  74.     info->mem = request_mem_region(res->start, size, pdev->name);  
  75.     if (info->mem == NULL) {  
  76.         dev_err(&pdev->dev, "failed to get memory region\n");  
  77.         ret = -ENOENT;  
  78.         goto dealloc_fb;  
  79.     }  
  80.   
  81.     /* 映射I/O地址,其实就是将S3C2440的LCD首寄存器(LCDCON1)的物理地址映射为虚拟地址 */  
  82.     info->io = ioremap(res->start, size);  
  83.     if (info->io == NULL) {  
  84.         dev_err(&pdev->dev, "ioremap() of registers failed\n");  
  85.         ret = -ENXIO;  
  86.         goto release_mem;  
  87.     }  
  88.   
  89.     /* 这里相当于info->irq_base = info->io + 0x54,刚好是LCDINTPND寄存器的地址 */  
  90.     info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);  
  91.   
  92.     dprintk("devinit\n");  
  93.   
  94.     /* 驱动名,fbinfo->fix.id = s3c2410fb */  
  95.     strcpy(fbinfo->fix.id, driver_name);   
  96.   
  97.     /* Stop the video */  
  98.     lcdcon1 = readl(info->io + S3C2410_LCDCON1);  
  99.     /* 禁止Video output */  
  100.     writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);  
  101.   
  102.     /* 设置fb_info结构体通用的固定参数fb_fix_screeninfo结构体 */  
  103.     fbinfo->fix.type         = FB_TYPE_PACKED_PIXELS;  
  104.     fbinfo->fix.type_aux     = 0;  
  105.     fbinfo->fix.xpanstep     = 0;  
  106.     fbinfo->fix.ypanstep     = 0;  
  107.     fbinfo->fix.ywrapstep        = 0;  
  108.     fbinfo->fix.accel            = FB_ACCEL_NONE;    /* 无硬件加速 */  
  109.   
  110.     /* 设置fb_info结构体通用的可变参数fb_var_screeninfo结构体 */  
  111.     fbinfo->var.nonstd           = 0;  
  112.     fbinfo->var.activate     = FB_ACTIVATE_NOW;  
  113.     fbinfo->var.accel_flags     = 0;  
  114.     fbinfo->var.vmode            = FB_VMODE_NONINTERLACED;  
  115.   
  116.     /* 设置fb_ops结构体 */  
  117.     fbinfo->fbops                = &s3c2410fb_ops;  
  118.       
  119.     fbinfo->flags                = FBINFO_FLAG_DEFAULT;  
  120.   
  121.     /* 设置假调色板 */  
  122.     fbinfo->pseudo_palette      = &info->pseudo_pal;  
  123.   
  124.     /* palette_buffer[i] = 0x80000000,清空调色板 */  
  125.     for (i = 0; i < 256; i++)  
  126.         info->palette_buffer[i] = PALETTE_BUFF_CLEAR;  
  127.   
  128.     /* 申请中断,s3c2410fb_irq是中断处理函数 */  
  129.     ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);  
  130.     if (ret) {  
  131.         dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);  
  132.         ret = -EBUSY;  
  133.         goto release_regs;  
  134.     }  
  135.   
  136.     /* 获取lcd时钟 */  
  137.     info->clk = clk_get(NULL, "lcd");  
  138.     if (!info->clk || IS_ERR(info->clk)) {  
  139.         printk(KERN_ERR "failed to get lcd clock source\n");  
  140.         ret = -ENOENT;  
  141.         goto release_irq;  
  142.     }  
  143.   
  144.     /* 使能lcd时钟 */  
  145.     clk_enable(info->clk);         
  146.     dprintk("got and enabled clock\n");  
  147.   
  148.     msleep(1);  
  149.   
  150.     /* find maximum required memory size for display */  
  151.   
  152.     /* 计算出lcd的显存大小,显存大小为width * height * bpp所以还要左移3位, 
  153.      * 即刚好一帧大小空间,前面计算出来的是多少bit,计算出显存为多少字节。 
  154.      * 显示配置有可能有多个,所以呢,这个for循环计算出的是最大显存大小。 
  155.      */  
  156.     for (i = 0; i < mach_info->num_displays; i++) {           /* 这里mach_info->num_displays = 1 */  
  157.         unsigned long smem_len = mach_info->displays[i].xres;    /* x方向分辨率 */  
  158.   
  159.         smem_len *= mach_info->displays[i].yres;             /* y方向分辨率 */  
  160.         smem_len *= mach_info->displays[i].bpp;                  /* bpp */  
  161.         smem_len >>= 3;                                           /* smem_len除以8 */  
  162.         if (fbinfo->fix.smem_len < smem_len)  
  163.             fbinfo->fix.smem_len = smem_len;  
  164.     }  
  165.   
  166.     /* Initialize video memory */  
  167.     ret = s3c2410fb_map_video_memory(fbinfo);   /* 分配显存 */  
  168.     if (ret) {  
  169.         printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);  
  170.         ret = -ENOMEM;  
  171.         goto release_clock;  
  172.     }  
  173.   
  174.     dprintk("got video memory\n");  
  175.   
  176.     /* display指向tq2440_lcd_cfg */  
  177.     fbinfo->var.xres = display->xres;         /* 设置x方向的分辨率 */  
  178.     fbinfo->var.yres = display->yres;         /* 设置y方向的分辨率 */  
  179.     fbinfo->var.bits_per_pixel = display->bpp;    /* 设置bpp位数 */  
  180.   
  181.     /* 初始化LCD相关的寄存器 */  
  182.     s3c2410fb_init_registers(fbinfo);  
  183.   
  184.     /* 检查可变参数 */  
  185.     s3c2410fb_check_var(&fbinfo->var, fbinfo);  
  186.   
  187.     /* 注册fb_info结构体 */  
  188.     ret = register_framebuffer(fbinfo);  
  189.     if (ret < 0) {  
  190.         printk(KERN_ERR "Failed to register framebuffer device: %d\n",  
  191.             ret);  
  192.         goto free_video_memory;  
  193.     }  
  194.   
  195.     /* create device files */  
  196.     ret = device_create_file(&pdev->dev, &dev_attr_debug);  
  197.     if (ret) {  
  198.         printk(KERN_ERR "failed to add debug attribute\n");  
  199.     }  
  200.   
  201.   
  202.     /* TQ2440开发板内核启动时打印的信息,fb0: s3c2410fb frame buffer device  */  
  203.     printk(KERN_INFO "fb%d: %s frame buffer device\n",  
  204.         fbinfo->node, fbinfo->fix.id);  
  205.   
  206.     return 0;  
  207.   
  208. free_video_memory:  
  209.     s3c2410fb_unmap_video_memory(fbinfo);  
  210. release_clock:  
  211.     clk_disable(info->clk);              /* 禁止lcd时钟 */  
  212.     clk_put(info->clk);                  /* 删除lcd时钟 */  
  213. release_irq:  
  214.     free_irq(irq, info);                /* 释放IRQ */  
  215. release_regs:  
  216.     iounmap(info->io);                   /* 解除映射 */  
  217. release_mem:  
  218.     release_resource(info->mem);     /* 释放资源 */  
  219.     kfree(info->mem);                    /* 释放刚申请的内存 */  
  220. dealloc_fb:  
  221.     platform_set_drvdata(pdev, NULL);   /* 相当于pdev->dev->driver_data = NULL */  
  222.     framebuffer_release(fbinfo);        /* 释放fb_info结构体 */  
  223.     return ret;  
  224. }  
拆分详解:

一、获得平台数据

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. mach_info = pdev->dev.platform_data;  
  2.   
  3. /* 执行完上面的语句后mach_info指向tq2440_fb_info结构体,而不为NULL  */  
  4. if (mach_info == NULL) {  
  5.     dev_err(&pdev->dev,  
  6.         "no platform data for lcd, cannot attach\n");  
  7.     return -EINVAL;     /* 表示无效的参数 */  
  8. }  
s3c24xx_fb_set_platdata()里会设置platform_data,tq2440_machine_init()函数调用s3c24xx_fb_set_platdata(&tq2440_fb_info);
所以这里传入来的platform_data就是tq2440_fb_info结构体实例。

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. static void __init tq2440_machine_init(void)  
  2. {  
  3.     /* 初始化tq2440_fb_info实体结构体 */  
  4.     s3c24xx_fb_set_platdata(&tq2440_fb_info);  
  5.     s3c_i2c0_set_platdata(NULL);  
  6.   
  7.     /* 添加tq2440_devices到内核,它是platform_device类的设备 */  
  8.     platform_add_devices(tq2440_devices, ARRAY_SIZE(tq2440_devices));  
  9.     EmbedSky_machine_init();  
  10.     s3c2410_gpio_setpin(S3C2410_GPG12, 0);  
  11.     s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPIO_OUTPUT);  
  12.     s3c24xx_udc_set_platdata(&EmbedSky_udc_cfg);  
  13. }  
s3c24xx_fb_set_platdata函数将tq2440_fb_info拷贝到s3c2410fb_mach_info,并将s3c_device_lcd.dev.platform_data指向tq2440_fb_info

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)  
  2. {  
  3.     struct s3c2410fb_mach_info *npd;  
  4.   
  5.     /* 申请分配s3c2410fb_mach_info大小的内存 */  
  6.     npd = kmalloc(sizeof(*npd), GFP_KERNEL);  
  7.     if (npd) {  
  8.         /* 拷贝s3c2410fb_mach_info型实体给npd */  
  9.         memcpy(npd, pd, sizeof(*npd));  
  10.   
  11.         /* 最后将s3c2410fb_mach_info型实体赋给platform_data */  
  12.         s3c_device_lcd.dev.platform_data = npd;  
  13.     } else {  
  14.         printk(KERN_ERR "no memory for LCD platform data\n");  
  15.     }  
  16. }  
二、设置s3c2410fb_display指向tq2440_lcd_cfg

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* tq2440_fb_info设置了default_display = 0,num_displays = 1,故这句不会执行 */  
  2. if (mach_info->default_display >= mach_info->num_displays) {  
  3.     dev_err(&pdev->dev, "default is %d but only %d displays\n",  
  4.         mach_info->default_display, mach_info->num_displays);  
  5.     return -EINVAL;  
  6. }  
  7.   
  8. /* display指向tq2440_lcd_cfg,关于LCD屏相关参数的设置 */  
  9. display = mach_info->displays + mach_info->default_display;  
三、获得IRQ资源

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. irq = platform_get_irq(pdev, 0);  
  2. if (irq < 0) {  
  3.     dev_err(&pdev->dev, "no irq for device\n");  
  4.     return -ENOENT;  
  5. }  
四、分配fb_info内存
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);  
  2.     if (!fbinfo)  
  3.         return -ENOMEM;     /* 返回NULL表示失败 */  
framebuffer_alloc第一参数不为0表示,额外多申请的空间,用来存放额外的数据,这里用来存放s3c2410fb_info额外的数据,比如:clk,resource,io,irq_base,drv_type等额外信息。
五、设置s3c2410fb_info结构体

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* 相当于pdev->dev->driver_data = fbinfo */  
  2.     platform_set_drvdata(pdev, fbinfo);  
  3.   
  4.     /* 在framebuffer_alloc函数里info->par指向了额外多申请内存空间的首地址 */  
  5.     info = fbinfo->par;          /* 将私有数据赋给info指针变量 */  
  6.     info->dev = &pdev->dev;       /* 指定struct s3c2410fb_info中dev为平台设备中的dev */  
  7.     info->drv_type = drv_type;   /* 驱动类型, DRV_S3C2410还是DRV_S3C2412 */  
六、获取IO资源,映射IO

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /*  通过平台设备platform_device获得资源(IO) */  
  2.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  3.     if (res == NULL) {  
  4.         dev_err(&pdev->dev, "failed to get memory registers\n");  
  5.         ret = -ENXIO;  
  6.         goto dealloc_fb;  
  7.     }  
  8.   
  9.     size = (res->end - res->start) + 1;       /* 资源的大小 */  
  10.   
  11.     /* 申请以res->start地址开始大小为size的I/O内存 */  
  12.     info->mem = request_mem_region(res->start, size, pdev->name);  
  13.     if (info->mem == NULL) {  
  14.         dev_err(&pdev->dev, "failed to get memory region\n");  
  15.         ret = -ENOENT;  
  16.         goto dealloc_fb;  
  17.     }  
  18.   
  19.     /* 映射I/O地址,其实就是将S3C2440的LCD首寄存器(LCDCON1)的物理地址映射为虚拟地址 */  
  20.     info->io = ioremap(res->start, size);  
  21.     if (info->io == NULL) {  
  22.         dev_err(&pdev->dev, "ioremap() of registers failed\n");  
  23.         ret = -ENXIO;  
  24.         goto release_mem;  
  25.     }  
  26.   
  27.     /* 这里相当于info->irq_base = info->io + 0x54,刚好是LCDINTPND寄存器的地址 */  
  28.     info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);  
七、读写LCDCON1,禁止视频数据输出

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* Stop the video */  
  2. lcdcon1 = readl(info->io + S3C2410_LCDCON1);  
  3. /* 禁止Video output */  
  4. writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);  
八、设置fb_info结构体的固定参数(fb_fix_screeninfo),可变参数(fb_var_screeninfo),fbops结构体,flags,假调色板(pseudo_palette)等

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* 设置fb_info结构体通用的固定参数fb_fix_screeninfo结构体 */  
  2.     fbinfo->fix.type         = FB_TYPE_PACKED_PIXELS;  
  3.     fbinfo->fix.type_aux     = 0;  
  4.     fbinfo->fix.xpanstep     = 0;  
  5.     fbinfo->fix.ypanstep     = 0;  
  6.     fbinfo->fix.ywrapstep        = 0;  
  7.     fbinfo->fix.accel            = FB_ACCEL_NONE;    /* 无硬件加速 */  
  8.   
  9.     /* 设置fb_info结构体通用的可变参数fb_var_screeninfo结构体 */  
  10.     fbinfo->var.nonstd           = 0;  
  11.     fbinfo->var.activate     = FB_ACTIVATE_NOW;  
  12.     fbinfo->var.accel_flags     = 0;  
  13.     fbinfo->var.vmode            = FB_VMODE_NONINTERLACED;  
  14.   
  15.     /* 设置fb_ops结构体 */  
  16.     fbinfo->fbops                = &s3c2410fb_ops;  
  17.       
  18.     fbinfo->flags                = FBINFO_FLAG_DEFAULT;  
  19.   
  20.     /* 设置假调色板 */  
  21.     fbinfo->pseudo_palette      = &info->pseudo_pal;  
  22.   
  23.     /* palette_buffer[i] = 0x80000000,清空调色板 */  
  24.     for (i = 0; i < 256; i++)  
  25.         info->palette_buffer[i] = PALETTE_BUFF_CLEAR;  
九、申请中断、获取LCD时钟,使能LCD时钟
[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* 申请中断,s3c2410fb_irq是中断处理函数 */  
  2. ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);  
  3. if (ret) {  
  4.     dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);  
  5.     ret = -EBUSY;  
  6.     goto release_regs;  
  7. }  
  8.   
  9. /* 获取lcd时钟 */  
  10. info->clk = clk_get(NULL, "lcd");  
  11. if (!info->clk || IS_ERR(info->clk)) {  
  12.     printk(KERN_ERR "failed to get lcd clock source\n");  
  13.     ret = -ENOENT;  
  14.     goto release_irq;  
  15. }  
  16.   
  17. /* 使能lcd时钟 */  
  18. clk_enable(info->clk);         
  19. dprintk("got and enabled clock\n");  
十、计算显存大小、分配显存内存

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* 计算出lcd的显存大小,显存大小为width * height * bpp所以还要左移3位, 
  2.     * 即刚好一帧大小空间,前面计算出来的是多少bit,计算出显存为多少字节。 
  3.     * 显示配置有可能有多个,所以呢,这个for循环计算出的是最大显存大小。 
  4.  */  
  5. for (i = 0; i < mach_info->num_displays; i++) {           /* 这里mach_info->num_displays = 1 */  
  6.     unsigned long smem_len = mach_info->displays[i].xres;    /* x方向分辨率 */  
  7.   
  8.     smem_len *= mach_info->displays[i].yres;             /* y方向分辨率 */  
  9.     smem_len *= mach_info->displays[i].bpp;                  /* bpp */  
  10.     smem_len >>= 3;                                           /* smem_len除以8 */  
  11.     if (fbinfo->fix.smem_len < smem_len)  
  12.         fbinfo->fix.smem_len = smem_len;  
  13. }  
  14.   
  15. /* Initialize video memory */  
  16. ret = s3c2410fb_map_video_memory(fbinfo);   /* 分配显存 */  
  17. if (ret) {  
  18.     printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);  
  19.     ret = -ENOMEM;  
  20.     goto release_clock;  
  21. }  
十一、设置fb_info结构体中的可变参数的x、y分辨率以及BPP为tq2440_lcd_cfg中的x、y分辨率和BPP

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* display指向tq2440_lcd_cfg */  
  2. fbinfo->var.xres = display->xres;         /* 设置x方向的分辨率 */  
  3. fbinfo->var.yres = display->yres;         /* 设置y方向的分辨率 */  
  4. fbinfo->var.bits_per_pixel = display->bpp;    /* 设置bpp位数 */  
十二、LCD相关寄存器的设置和fb_info的可变参数的检测

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* 初始化LCD相关的寄存器 */  
  2.     s3c2410fb_init_registers(fbinfo);  
  3.   
  4.     /* 检查可变参数 */  
  5.     s3c2410fb_check_var(&fbinfo->var, fbinfo);  
十三、注册fb_info结构体

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* 注册fb_info结构体 */  
  2. ret = register_framebuffer(fbinfo);  
  3. if (ret < 0) {  
  4.     printk(KERN_ERR "Failed to register framebuffer device: %d\n",  
  5.         ret);  
  6.     goto free_video_memory;  
  7. }  
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 武商购物卡过期怎么办 丹尼斯卡过期了怎么办 联华ok卡过期了怎么办 汉购通过期了怎么办 天猫退货要检测报告怎么办 京东退货后发票怎么办 京东金融被盗刷怎么办 京东e卡丢了怎么办 京东e卡没有密码怎么办 同一个订单微信付款两次怎么办 京东购物卡掉了怎么办 京东购物卡丢了怎么办 京东快递丢了怎么办 京东e卡支付多了怎么办 京东帐号忘了怎么办 京东白条风控怎么办 我有个破袄…没有衣服怎么办办 轩辕传奇手游灵宠融合错了怎么办 各尧学生不能用怎么办? 山东一卡通商务卡丢了怎么办 和信通过期了怎么办 和信通过期怎么办延期 和信通过期余额怎么办 超市储蓄卡丢了怎么办 提现提到注销卡怎么办 美通卡过期2年了怎么办 物美美通卡丢失怎么办 网上购物电话留错了怎么办 微信斗牛一直输怎么办 微信斗牛输了钱怎么办 微信举报诈骗不成功该怎么办 沙河拿服装太贵怎么办 包上的暗扣掉了怎么办 银手镯暗扣松老是掉怎么办 包包纽扣锁坏了怎么办 包的纽扣坏了怎么办 包上的纽扣坏了怎么办 洗衣服不小心用了色渍净怎么办 洗衣服不小心沾了卫生纸怎么办 麻料裤子扎皮肤怎么办 衣服没洗干净有点发光怎么办