上一节中,分析了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. python学习笔记(arange函数与linspace函数)

    上一篇提及到matplotlib模块.其中会涉及到numpy模块科学计数 这里总结两个数组生成函数 arange 与 linspace: #!/usr/bin/env python # -*- cod ...

  2. 使用科大讯飞时碰上的问题(unity调用Android)

    使用科大讯飞的时候公司已经有人配置好了Android项目,由于装机量的限制,所以基本上要更换里面的资源和更改app_id,然而在unity那边调用的时候总是出现各种各样的问题,特此记录下来 1.唤醒未 ...

  3. 不能在Python Console中运行pytest

    在Python Console中运行pytest发现报错了 这是为什么?因为Python Console已经是进入python之后的环境,就像在python自带的IDLE中运行pytest pytes ...

  4. TCP/UDP编程步骤和区别

    一. 概念解析 套接字:一种特殊的文件描述符.一头指向套接字地址(用户),一头指向套接字结构(内核). 套接字结构:由内核维持的一种数据结构,可通过套接字来操作. 套接字地址:ip和port. 二. ...

  5. 上传图片到阿里云oss

    阿里云地址 登录阿里云管理控制台,创建对象存储oss private static final String endpoint = "http://oss-cn-shanghai.aliyu ...

  6. 011-对象——interface接口说明与使用方式实例

    <?php /** interface接口说明与使用方式实例 * * 接口里面的方法全是抽象方法,没有实体的方法.这样的类我们就叫做接口.定义的时候用Interface定义.实现接口时用impl ...

  7. TCPL学习笔记:4-12以及4-13。关于使用递归的问题。

    4-12.写一个函数itoa,通过递归调用将整数转换成为字符串. #include <stdio.h> #include <stdlib.h> void Itoa(int nu ...

  8. SpringCloud 教程 | 第十四篇: 服务注册(consul)

    版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 ,博主地址:http://blog.csdn.net/forezp. http://blog.csdn.net/forezp/art ...

  9. Audio/Movie/Image

    Audio 1. 引入AVFoundation 库,此库用于处理音频的播放. > 使用AVAudioPlayer 播放音频,此类只能播放本地音频文件.对于流媒体(边下边播)的播放使用第三方框架实 ...

  10. 2017.10.26 ECN + product spec+ cypress ble module test+

    1 ECN Ecn  should be issued when modifying drawing,Copy children BOM of subassembly from BIL if one ...