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

上一节文章链接:http://blog.csdn.net/lwj103862095/article/details/18188259

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

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

拆分详解:

一、获得平台数据

[cpp] view
plain
?
  1. mach_info = pdev->dev.platform_data;
  2. /* 执行完上面的语句后mach_info指向tq2440_fb_info结构体,而不为NULL  */
  3. if (mach_info == NULL) {
  4. dev_err(&pdev->dev,
  5. "no platform data for lcd, cannot attach\n");
  6. return -EINVAL;     /* 表示无效的参数 */
  7. }

s3c24xx_fb_set_platdata()里会设置platform_data,tq2440_machine_init()函数调用s3c24xx_fb_set_platdata(&tq2440_fb_info);

所以这里传入来的platform_data就是tq2440_fb_info结构体实例。

[cpp] view
plain
?
  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. /* 添加tq2440_devices到内核,它是platform_device类的设备 */
  7. platform_add_devices(tq2440_devices, ARRAY_SIZE(tq2440_devices));
  8. EmbedSky_machine_init();
  9. s3c2410_gpio_setpin(S3C2410_GPG12, 0);
  10. s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPIO_OUTPUT);
  11. s3c24xx_udc_set_platdata(&EmbedSky_udc_cfg);
  12. }

s3c24xx_fb_set_platdata函数将tq2440_fb_info拷贝到s3c2410fb_mach_info,并将s3c_device_lcd.dev.platform_data指向tq2440_fb_info

[cpp] view
plain
?
  1. void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
  2. {
  3. struct s3c2410fb_mach_info *npd;
  4. /* 申请分配s3c2410fb_mach_info大小的内存 */
  5. npd = kmalloc(sizeof(*npd), GFP_KERNEL);
  6. if (npd) {
  7. /* 拷贝s3c2410fb_mach_info型实体给npd */
  8. memcpy(npd, pd, sizeof(*npd));
  9. /* 最后将s3c2410fb_mach_info型实体赋给platform_data */
  10. s3c_device_lcd.dev.platform_data = npd;
  11. } else {
  12. printk(KERN_ERR "no memory for LCD platform data\n");
  13. }
  14. }

二、设置s3c2410fb_display指向tq2440_lcd_cfg

[cpp] view
plain
?
  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. /* display指向tq2440_lcd_cfg,关于LCD屏相关参数的设置 */
  8. display = mach_info->displays + mach_info->default_display;

三、获得IRQ资源

[cpp] view
plain
?
  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
?
  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
?
  1. /* 相当于pdev->dev->driver_data = fbinfo */
  2. platform_set_drvdata(pdev, fbinfo);
  3. /* 在framebuffer_alloc函数里info->par指向了额外多申请内存空间的首地址 */
  4. info = fbinfo->par;          /* 将私有数据赋给info指针变量 */
  5. info->dev = &pdev->dev;       /* 指定struct s3c2410fb_info中dev为平台设备中的dev */
  6. info->drv_type = drv_type;   /* 驱动类型, DRV_S3C2410还是DRV_S3C2412 */

六、获取IO资源,映射IO

[cpp] view
plain
?
  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. size = (res->end - res->start) + 1;       /* 资源的大小 */
  9. /* 申请以res->start地址开始大小为size的I/O内存 */
  10. info->mem = request_mem_region(res->start, size, pdev->name);
  11. if (info->mem == NULL) {
  12. dev_err(&pdev->dev, "failed to get memory region\n");
  13. ret = -ENOENT;
  14. goto dealloc_fb;
  15. }
  16. /* 映射I/O地址,其实就是将S3C2440的LCD首寄存器(LCDCON1)的物理地址映射为虚拟地址 */
  17. info->io = ioremap(res->start, size);
  18. if (info->io == NULL) {
  19. dev_err(&pdev->dev, "ioremap() of registers failed\n");
  20. ret = -ENXIO;
  21. goto release_mem;
  22. }
  23. /* 这里相当于info->irq_base = info->io + 0x54,刚好是LCDINTPND寄存器的地址 */
  24. info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);

七、读写LCDCON1,禁止视频数据输出

[cpp] view
plain
?
  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
?
  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. /* 设置fb_info结构体通用的可变参数fb_var_screeninfo结构体 */
  9. fbinfo->var.nonstd           = 0;
  10. fbinfo->var.activate     = FB_ACTIVATE_NOW;
  11. fbinfo->var.accel_flags     = 0;
  12. fbinfo->var.vmode            = FB_VMODE_NONINTERLACED;
  13. /* 设置fb_ops结构体 */
  14. fbinfo->fbops                = &s3c2410fb_ops;
  15. fbinfo->flags                = FBINFO_FLAG_DEFAULT;
  16. /* 设置假调色板 */
  17. fbinfo->pseudo_palette      = &info->pseudo_pal;
  18. /* palette_buffer[i] = 0x80000000,清空调色板 */
  19. for (i = 0; i < 256; i++)
  20. info->palette_buffer[i] = PALETTE_BUFF_CLEAR;

九、申请中断、获取LCD时钟,使能LCD时钟

[cpp] view
plain
?
  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. /* 获取lcd时钟 */
  9. info->clk = clk_get(NULL, "lcd");
  10. if (!info->clk || IS_ERR(info->clk)) {
  11. printk(KERN_ERR "failed to get lcd clock source\n");
  12. ret = -ENOENT;
  13. goto release_irq;
  14. }
  15. /* 使能lcd时钟 */
  16. clk_enable(info->clk);
  17. dprintk("got and enabled clock\n");

十、计算显存大小、分配显存内存

[cpp] view
plain
?
  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. smem_len *= mach_info->displays[i].yres;             /* y方向分辨率 */
  8. smem_len *= mach_info->displays[i].bpp;                  /* bpp */
  9. smem_len >>= 3;                                           /* smem_len除以8 */
  10. if (fbinfo->fix.smem_len < smem_len)
  11. fbinfo->fix.smem_len = smem_len;
  12. }
  13. /* Initialize video memory */
  14. ret = s3c2410fb_map_video_memory(fbinfo);   /* 分配显存 */
  15. if (ret) {
  16. printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
  17. ret = -ENOMEM;
  18. goto release_clock;
  19. }

十一、设置fb_info结构体中的可变参数的x、y分辨率以及BPP为tq2440_lcd_cfg中的x、y分辨率和BPP

[cpp] view
plain
?
  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
?
  1. /* 初始化LCD相关的寄存器 */
  2. s3c2410fb_init_registers(fbinfo);
  3. /* 检查可变参数 */
  4. s3c2410fb_check_var(&fbinfo->var, fbinfo);

十三、注册fb_info结构体

[cpp] view
plain
?
  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. }

linux lcd设备驱动剖析二的更多相关文章

  1. linux lcd设备驱动剖析四

    在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...

  2. linux lcd设备驱动剖析一

    s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c 看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数 [cpp] view plain? ...

  3. linux lcd设备驱动剖析三

    上一节文章中详细地剖析了probe函数,但是从始至终都没有看到打开读写文件接口的操作函数,只看到了下面这个操作结构体 [cpp] view plain? static struct fb_ops s3 ...

  4. 【VS开发】【DSP开发】浅谈Linux PCI设备驱动(二)

    我们在 浅谈Linux PCI设备驱动(一)中(以下简称 浅谈(一) )介绍了PCI的配置寄存器组,而Linux PCI初始化就是使用了这些寄存器来进行的.后面我们会举个例子来说明Linux PCI设 ...

  5. Linux 块设备驱动 (二)

    linux下Ramdisk驱动 1 什么是Ramdisk Ramdisk是一种模拟磁盘,其数据实际上是存储在RAM中,它使用一部分内存空间来模拟出一个磁盘设备,并以块设备的方式来组织和访问这片内存.对 ...

  6. linux 块设备驱动(二)——块设备数据结构

    本文来源于: 1. http://www.cnblogs.com/dyllove98/archive/2013/07/01/3165567.html 块设备相关的数据结构以及接口: 块设备接口则相对复 ...

  7. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  8. Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...

  9. Linux FC/iSCSI存储设备管理系列(一):Linux系统设备驱动入门

    Linux FC/iSCSI存储设备管理系列(一):Linux系统设备驱动入门 转载请在文首保留原文出处:EMC中文支持论坛 - https://community.emc.com/go/chines ...

随机推荐

  1. d2.js学习笔记(七)——动态SVG坐标空间

    目标 在这一章,我们将学习如何使SVG坐标空间是动态的,这样我们的数据可视化不论数据是什么,都始终是可见的. 我们会使得SVG坐标空间尺度上调或下调来适于我们的数据. 三个SVG长方形 我们就从三个长 ...

  2. dypedef 和 define

    typedef char *String_t; 和 #define String_dchar * 这两句在使用上有什么区别? 答:typedef char *String_t 定义了一个新的类型别名, ...

  3. python之linecache使用

    Python linecache模块缓存读取大文件指定行 linecache模块的作用是将文件内容读取到内存中,进行缓存,而不是每次都要从硬盘中读取,这样效率提高很多,又省去了对硬盘IO控制器的频繁操 ...

  4. requirejs打包项目

    例子: https://github.com/AinneShen/requirejsExample 用requirejs为js和css添加版本,项目共用同一个config

  5. PhantomJS 和Selenium模拟页面js点击

    由于自己不怎么会javascripts,无法找全所有的参数进行模拟提交,所以只能寻求Selenium和PhantpmJS的方式. 先说下ubuntu上怎么安装相应的环境,尤其PhantomJS安装比较 ...

  6. 【spark】SparkSession的API

    SparkSession是一个比较重要的类,它的功能的实现,肯定包含比较多的函数,这里介绍下它包含哪些函数. builder函数public static SparkSession.Builder b ...

  7. Tomcat和Servlet

    Tomcat Tomcat是什么,Tomcat是目前市场上主流Web服务器之一,是用Java语言开发的项目.Tomcat支持Servlet和JSP的规范,它由一组嵌套的层次和组件组成.结构如下图 所有 ...

  8. 【python】没有root权限的时候安装Python package

    下载相关位置的包 1.首先在git上下载对应的包: 搜索package github,找到地址.使用 git clone https://xxx.git 命令 2.使用python setup.py ...

  9. How your script code be coverted into arm code and running on ios.

    Your script code is compiled into DLLs (assemblies) by the editor. When you build for iOS, these ass ...

  10. [QT][问题记录]发布软件时遇到的问题

    2017-3-9 11:22:13 无法定位程序输入点 _ZdaPvj 于动态链接库 libstdc++-6.dll 上. 这是在自己机器上出现的问题. 使用cmd 进行命令 windeployqt  ...