转自:http://www.cnblogs.com/armlinux/archive/2012/03/01/2396753.html

45 struct fb_info *registered_fb[FB_MAX] __read_mostly;

这个是全局的变量,通过这个全局变量,在系统内可以随时获取需要的fb_info,具体的获取方法是

通过比对 registered_fb[i]->fix.id来确定需要的fb_info, 示例代码如下

for (i = 0; i < num_registered_fb; i++) {
        char *idstr = registered_fb[i]->fix.id;
        if (strcmp(idstr, "DISP3 FG") == 0) {
            fbi = registered_fb[i];
            break;
        }
    }

63 int fb_get_color_depth(struct fb_var_screeninfo *var,
  64                struct fb_fix_screeninfo *fix)
  65 {  
  66     int depth = 0;
  67
  68     if (fix->visual == FB_VISUAL_MONO01 ||
  69         fix->visual == FB_VISUAL_MONO10)
  70         depth = 1;
  71     else {
  72         if (var->green.length == var->blue.length &&
  73             var->green.length == var->red.length &&
  74             var->green.offset == var->blue.offset &&
  75             var->green.offset == var->red.offset)
  76             depth = var->green.length;
  77         else
  78             depth = var->green.length + var->red.length +
  79                 var->blue.length;
  80     }
  81
  82     return depth;
  83 }

该函数获取颜色深度,很简单啊,对于单色深度为1,否则深度为red blue green三个分量的和

129 char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
130 {
131     u32 align = buf->buf_align - 1, offset;
132     char *addr = buf->addr;
133
134     /* If IO mapped, we need to sync before access, no sharing of
135      * the pixmap is done
136      */
137     if (buf->flags & FB_PIXMAP_IO) {
138         if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
139             info->fbops->fb_sync(info);
140         return addr;
141     }
142
143     /* See if we fit in the remaining pixmap space */
144     offset = buf->offset + align;
145     offset &= ~align;
146     if (offset + size > buf->size) {
147         /* We do not fit. In order to be able to re-use the buffer,
148          * we must ensure no asynchronous DMA'ing or whatever operation
149          * is in progress, we sync for that.
150          */
151         if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
152             info->fbops->fb_sync(info);
153         offset = 0;
154     }
155     buf->offset = offset + size;
156     addr += offset;
157
158     return addr;
159 }

这个函数看似简单,就是获取@buf中符合@size大小的空闲位置

146行 如果剩余空间小于需要的大小,那么fb_sync后就可以使用@buffer的所有空间

这个函数看起来总是怪挂的,因为fb_sync的参数没有涉及到@buf, 所以fb_sync跟@buf有毛关系呀

虽然调用fb_get_buffer_offset时的@info和@buf的关系是@info->pixmap == @buf,那为毛不只传一个参数?

168 static void fb_set_logocmap(struct fb_info *info,
169                    const struct linux_logo *logo)
170 {
171     struct fb_cmap palette_cmap;
172     u16 palette_green[16];
173     u16 palette_blue[16];
174     u16 palette_red[16];
175     int i, j, n;
176     const unsigned char *clut = logo->clut;
177
178     palette_cmap.start = 0;
179     palette_cmap.len = 16;
180     palette_cmap.red = palette_red;
181     palette_cmap.green = palette_green;
182     palette_cmap.blue = palette_blue;#define FB_VISUAL_MONO01        0   /* Monochr. 1=Black 0=White */
183     palette_cmap.transp = NULL;
184
185     for (i = 0; i < logo->clutsize; i += n) {
186         n = logo->clutsize - i;
187         /* palette_cmap provides space for only 16 colors at once */
188         if (n > 16)
189             n = 16;
190         palette_cmap.start = 32 + i;
191         palette_cmap.len = n;
192         for (j = 0; j < n; ++j) {
193             palette_cmap.red[j] = clut[0] << 8 | clut[0];
194             palette_cmap.green[j] = clut[1] << 8 | clut[1];
195             palette_cmap.blue[j] = clut[2] << 8 | clut[2];
196             clut += 3;
197         }
198         fb_set_cmap(&palette_cmap, info);
199     }
200 }

在介绍这个函数前,先了解下调色板

在linux系统中,支持以下几种色彩模式

#define FB_VISUAL_MONO01   0

#define FB_VISUAL_MONO10        1   /* Monochr. 1=White 0=Black */
#define FB_VISUAL_TRUECOLOR     2   /* True color   */
#define FB_VISUAL_PSEUDOCOLOR       3   /* Pseudo color (like atari) */
#define FB_VISUAL_DIRECTCOLOR       4   /* Direct color */

FB_VISUAL_MONO10 FB_VISUAL_MONO01 每个像素为黑或者白

FB_VISUAL_TRUECOLOR 真彩色,分为红蓝绿三基色

FB_VISUAL_PSEUDOCOLOR 伪彩色,采用索引颜色显示,需要根据颜色index查找colormap,找到相应的颜色值

FB_VISUAL_DIRECTORCOLOR 每个像素颜色也是由红绿蓝三种颜色组成,不过每个颜色都是索引值,需要查表

注意FB_VISUAL_PSEUDOCOLOR和FB_VISUAL_DIRECTORCOLOR都是使用颜色所以,需要查表

看下fb_cmap结构,这个结构定义了颜色表(color map)

struct fb_cmap {
    __u32 start;            /* 第一个entry, 没看出start的作用 */
    __u32 len;          /* 每个颜色分量的长度 */
    __u16 *red;         /* 红色分量  */
    __u16 *green;
    __u16 *blue;
    __u16 *transp;          /* 透明度,可以为空 */

};

结构linux_logo 描述了一个linux logo的全部信息

struct linux_logo {
    int type;           /* one of LINUX_LOGO_*, logo的类型 */
    unsigned int width; /* logo的宽度*/
    unsigned int height; /* logo的高度*/
    unsigned int clutsize;      /* LINUX_LOGO_CLUT224 only, 颜色查找表的尺寸 */
    const unsigned char *clut;  /* LINUX_LOGO_CLUT224 only, 颜色查找表*/
    const unsigned char *data; /* logo 文件数据,对于LINUX_LOGO_CLUT224,data保存的是查找表的位置 */
};

回头来看 fb_set_logocmap, 这个函数写的非常的恶心,我从来没见过这么恶心的kernel代码,当然我也够贱,非要分析如此恶心的代码

这个函数是一个大循环,要用log->clut这个colormap去设置@info device 的colormap,每次最多处理16x3个颜色索引

190         palette_cmap.start = 32 + i;

这里加了个32,很讨厌这种数字写法,这里之所以选32是因为CLUT224这种格式的index值从32直到255,即我们在linux_logo->data中只能找到0值,以及32~255之间的值

198         fb_set_cmap(&palette_cmap, info);

这个函数会设置硬件调色板以及info->cmap

202 static void  fb_set_logo_truepalette(struct fb_info *info,
203                         const struct linux_logo *logo,
204                         u32 *palette)
205 {
206     static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
207     unsigned char redmask, greenmask, bluemask;
208     int redshift, greenshift, blueshift;
209     int i;
210     const unsigned char *clut = logo->clut;
211
212     /*
213      * We have to create a temporary palette since console palette is only
214      * 16 colors long.
215      */
216     /* Bug: Doesn't obey msb_right ... (who needs that?) */
217     redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];
218     greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
219     bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];
220     redshift   = info->var.red.offset   - (8 - info->var.red.length);
221     greenshift = info->var.green.offset - (8 - info->var.green.length);
222     blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);
223
224     for ( i = 0; i < logo->clutsize; i++) {
225         palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
226                  safe_shift((clut[1] & greenmask), greenshift) |
227                  safe_shift((clut[2] & bluemask), blueshift));
228         clut += 3;
229     }
230 }

这个函数为FB_VISUAL_PSEUDOCOLOR彩色模式的logo生成一个调色板,从32开始是因为CLUT224只支持32~255范围内的index值

232 static void fb_set_logo_directpalette(struct fb_info *info,
233                          const struct linux_logo *logo,
234                          u32 *palette)
235 {
236     int redshift, greenshift, blueshift;
237     int i;
238
239     redshift = info->var.red.offset;
240     greenshift = info->var.green.offset;
241     blueshift = info->var.blue.offset;
242
243     for (i = 32; i < 32 + logo->clutsize; i++)
244         palette[i] = i << redshift | i << greenshift | i << blueshift;
245 }

为FB_VISUAL_DIRECTCOLOR彩色模式生成一个调色板,只需生成32 ~ clutsize

247 static void fb_set_logo(struct fb_info *info,
248                    const struct linux_logo *logo, u8 *dst,
249                    int depth)
250 {
251     int i, j, k;
252     const u8 *src = logo->data;
253     u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
254     u8 fg = 1, d;
255
256     switch (fb_get_color_depth(&info->var, &info->fix)) {
257     case 1:
258         fg = 1;
259         break;
260     case 2:
261         fg = 3;
262         break;
263     default:
264         fg = 7;
265         break;
266     }
267
268     if (info->fix.visual == FB_VISUAL_MONO01 ||
269         info->fix.visual == FB_VISUAL_MONO10)
270         fg = ~((u8) (0xfff << info->var.green.length));
271
272     switch (depth) {
273     case 4:
274         for (i = 0; i < logo->height; i++)
275             for (j = 0; j < logo->width; src++) {
276                 *dst++ = *src >> 4;
277                 j++;
278                 if (j < logo->width) {
279                     *dst++ = *src & 0x0f;
280                     j++;
281                 }
282             }
283         break;
284     case 1:
285         for (i = 0; i < logo->height; i++) {
286             for (j = 0; j < logo->width; src++) {
287                 d = *src ^ xor;
288                 for (k = 7; k >= 0; k--) {
289                     *dst++ = ((d >> k) & 1) ? fg : 0;
290                     j++;
291                 }
292             }
293         }
294         break;
295     }
296 }
297

linux_logo->data中保存的是logo的data数据,如果对于mono或者16

色的数据来说,linxu_logo->data内的每个字节保存的是多个像素点的数据,fb_set_logo这个函数根据颜色深度把linux_logo->data的数据转换到@dst中,@dst中的每个字节,代表这一个像素索引

参见源码注视就很好理解为什么要做转换了

298 /*
299  * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors),
300  * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on
301  * the visual format and color depth of the framebuffer, the DAC, the
302  * pseudo_palette, and the logo data will be adjusted accordingly.
303  *
304  * Case 1 - linux_logo_clut224:
305  * Color exceeds the number of console colors (16), thus we set the hardware DAC
306  * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set.
307  *
308  * For visuals that require color info from the pseudo_palette, we also construct
309  * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
  310  * will be set.
311  *
312  * Case 2 - linux_logo_vga16:
313  * The number of colors just matches the console colors, thus there is no need
314  * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie,
315  * each byte contains color information for two pixels (upper and lower nibble).
316  * To be consistent with fb_imageblit() usage, we therefore separate the two
317  * nibbles into separate bytes. The "depth" flag will be set to 4.
318  *
319  * Case 3 - linux_logo_mono:
320  * This is similar with Case 2.  Each byte contains information for 8 pixels.
321  * We isolate each bit and expand each into a byte. The "depth" flag will
322  * be set to 1.

323  */
324 static struct logo_data {
325     int depth;
326     int needs_directpalette;
327     int needs_truepalette;
328     int needs_cmapreset;
329     const struct linux_logo *logo;
330 } fb_logo __read_mostly;
@depth是logo的深度

@logo是linux_logo数据

332 static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
333 {
334     u32 size = width * height, i;
335
336     out += size - 1;
337
338     for (i = size; i--; )
339         *out-- = *in++;
340 }
341
342 static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
343 {
344     int i, j, h = height - 1;
345
346     for (i = 0; i < height; i++)
347         for (j = 0; j < width; j++)
348                 out[height * j + h - i] = *in++;
349 }
350
351 static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
352 {
353     int i, j, w = width - 1;
354
355     for (i = 0; i < height; i++)
356         for (j = 0; j < width; j++)
357             out[height * (w - j) + i] = *in++;
358 }

这几个函数再此验证了代码的恶心程度,没人知道ud, cw ccw是什么含义

393 static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
394                 int rotate, unsigned int num)
395 {
396     unsigned int x;
397
398     if (rotate == FB_ROTATE_UR) {
399         for (x = 0;
400              x < num && image->dx + image->width <= info->var.xres;
401              x++) {
402             info->fbops->fb_imageblit(info, image);
403             image->dx += image->width + 8;
404         }
405     } else if (rotate == FB_ROTATE_UD) {
406         for (x = 0; x < num && image->dx >= 0; x++) {
407             info->fbops->fb_imageblit(info, image);
408             image->dx -= image->width + 8;
409         }
410     } else if (rotate == FB_ROTATE_CW) {
411         for (x = 0;
412              x < num && image->dy + image->height <= info->var.yres;
413              x++) {
414             info->fbops->fb_imageblit(info, image);
415             image->dy += image->height + 8;
416         }
417     } else if (rotate == FB_ROTATE_CCW) {
418         for (x = 0; x < num && image->dy >= 0; x++) {
419             info->fbops->fb_imageblit(info, image);
420             image->dy -= image->height + 8;
421         }
422     }
423 }

显示@image内的logo数据, @rotate是旋转方式, @num没看懂社么意思阿

425 static int fb_show_logo_line(struct fb_info *info, int rotate,
426                  const struct linux_logo *logo, int y,
427                  unsigned int n)
428 {
429     u32 *palette = NULL, *saved_pseudo_palette = NULL;
430     unsigned char *logo_new = NULL, *logo_rotate = NULL;
431     struct fb_image image;
432
433     /* Return if the frame buffer is not mapped or suspended */
434     if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
435         info->flags & FBINFO_MODULE)
436         return 0;
437
438     image.depth = 8;
439     image.data = logo->data;
440
441     if (fb_logo.needs_cmapreset)
442         fb_set_logocmap(info, logo);
443
444     if (fb_logo.needs_truepalette ||
445         fb_logo.needs_directpalette) {
446         palette = kmalloc(256 * 4, GFP_KERNEL);
447         if (palette == NULL)
448             return 0;
449
450         if (fb_logo.needs_truepalette)
451             fb_set_logo_truepalette(info, logo, palette);
452         else
453             fb_set_logo_directpalette(info, logo, palette);
454
455         saved_pseudo_palette = info->pseudo_palette;
456         info->pseudo_palette = palette;
457     }
458
459     if (fb_logo.depth <= 4) {
460         logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
461         if (logo_new == NULL) {
462             kfree(palette);
463             if (saved_pseudo_palette)
464                 info->pseudo_palette = saved_pseudo_palette;
465             return 0;
466         }
467         image.data = logo_new;
468         fb_set_logo(info, logo, logo_new, fb_logo.depth);
469     }

470
471     image.dx = 0;
472     image.dy = y;
473     image.width = logo->width;
474     image.height = logo->height;
475
476     if (rotate) {
477         logo_rotate = kmalloc(logo->width *
478                       logo->height, GFP_KERNEL);
479         if (logo_rotate)
480             fb_rotate_logo(info, logo_rotate, &image, rotate);
481     }
482
483     fb_do_show_logo(info, &image, rotate, n);
484
485     kfree(palette);
486     if (saved_pseudo_palette != NULL)
487         info->pseudo_palette = saved_pseudo_palette;
488     kfree(logo_new);
489     kfree(logo_rotate);
490     return logo->height;
491 }

我无语了,这代码写的,为毛有个@y参数呀

503 void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
504 {
505     if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
506         return;
507
508     fb_logo_ex[fb_logo_ex_num].logo = logo;
509     fb_logo_ex[fb_logo_ex_num].n = n;
510     fb_logo_ex_num++;
511 }
这个函数把给定的logo设置到fb_logo_ex这个全局extend logo数组中, @n作用未知

513 static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
514                   unsigned int yres)
515 {
516     unsigned int i;
517
518     /* FIXME: logo_ex supports only truecolor fb. */
519     if (info->fix.visual != FB_VISUAL_TRUECOLOR)
520         fb_logo_ex_num = 0;
521
522     for (i = 0; i < fb_logo_ex_num; i++) {
523         if (fb_logo_ex[i].logo->type != fb_logo.logo->type) {
524             fb_logo_ex[i].logo = NULL;
525             continue;
526         }
527         height += fb_logo_ex[i].logo->height;
528         if (height > yres) {
529             height -= fb_logo_ex[i].logo->height;
530             fb_logo_ex_num = i;
531             break;
532         }
533     }
534     return height;
535 }

这段代码写的相当不好,单独引入的fb_logo_ex_num极其恶劣

这段代码的意思也就是计算height,以及fb_logo_ex_num

height是logo和有效extend logo的高度和,fb_log_ex_num是有效extend logo的最大索引

537 static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
538 {
539     unsigned int i;
540
541     for (i = 0; i < fb_logo_ex_num; i++)
542         y += fb_show_logo_line(info, rotate,
543                        fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
544
545     return y;
546 }

该函数显示保存在fb_logo_ex中的extend logo, @y表示这个extend logo要在屏幕显示的位置

565 int fb_prepare_logo(struct fb_info *info, int rotate)
566 {
567     int depth = fb_get_color_depth(&info->var, &info->fix);
568     unsigned int yres;
569
570     memset(&fb_logo, 0, sizeof(struct logo_data));
571
572     if (info->flags & FBINFO_MISC_TILEBLITTING ||
573         info->flags & FBINFO_MODULE)
574         return 0;
575
576     if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
577         depth = info->var.blue.length;
578         if (info->var.red.length < depth)
579             depth = info->var.red.length;
580         if (info->var.green.length < depth)
581             depth = info->var.green.length;
582     }
583
584     if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
585         /* assume console colormap */
586         depth = 4;
587     }
588
589     /* Return if no suitable logo was found */
590     fb_logo.logo = fb_find_logo(depth);
591
592     if (!fb_logo.logo) {
593         return 0;
594     }
595
596     if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
597         yres = info->var.yres;
598     else
599         yres = info->var.xres;
600
601     if (fb_logo.logo->height > yres) {
602         fb_logo.logo = NULL;
603         return 0;
604     }
605
606     /* What depth we asked for might be different from what we get */
607     if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
608         fb_logo.depth = 8;
609     else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
610         fb_logo.depth = 4;
611     else
612         fb_logo.depth = 1;
613
614
615     if (fb_logo.depth > 4 && depth > 4) {
616         switch (info->fix.visual) {
617         case FB_VISUAL_TRUECOLOR:
618             fb_logo.needs_truepalette = 1;
619             break;
620         case FB_VISUAL_DIRECTCOLOR:
621             fb_logo.needs_directpalette = 1;
622             fb_logo.needs_cmapreset = 1;
623             break;
624         case FB_VISUAL_PSEUDOCOLOR:
625             fb_logo.needs_cmapreset = 1;
626             break;
627         }
628     }
629
630     return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
631 }

到587行都是根据fb_info获取颜色depth

590根据depth获取合适的logo,  fb_find_logo看起来很简单,就是根据depth找到适合的logo

606~612 是根据获得的logo类型,计算logo的depth, 这可能和fb_find_logo传入的depth不一样

633 int fb_show_logo(struct fb_info *info, int rotate)
634 {
635     int y;
636
637     y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
638                   num_online_cpus());
639     y = fb_show_extra_logos(info, y, rotate);
640
641     return y;
642 }

先显示logo,fb_show_logo_line会返回logo占用的vertical height

然后在logo下显示extra logo, 传入的@y就是logo 的height

693 static ssize_t
694 fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
695 {
696     unsigned long p = *ppos;
697     struct inode *inode = file->f_path.dentry->d_inode;
698     int fbidx = iminor(inode);
699     struct fb_info *info = registered_fb[fbidx];
700     u32 *buffer, *dst;
701     u32 __iomem *src;
702     int c, i, cnt = 0, err = 0;
703     unsigned long total_size;
704
705     if (!info || ! info->screen_base)
706         return -ENODEV;
707
708     if (info->state != FBINFO_STATE_RUNNING)
709         return -EPERM;
710
711     if (info->fbops->fb_read)
712         return info->fbops->fb_read(info, buf, count, ppos);
713
714     total_size = info->screen_size;
715
716     if (total_size == 0)
717         total_size = info->fix.smem_len;
718
719     if (p >= total_size)
720         return 0;
721
722     if (count >= total_size)
723         count = total_size;
724
725     if (count + p > total_size)
726         count = total_size - p;
727
728     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
729              GFP_KERNEL);
730     if (!buffer)
731         return -ENOMEM;
732
733     src = (u32 __iomem *) (info->screen_base + p);
734
735     if (info->fbops->fb_sync)
736         info->fbops->fb_sync(info);
737
738     while (count) {
739         c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
740         dst = buffer;
741         for (i = c >> 2; i--; )
742             *dst++ = fb_readl(src++);
743         if (c & 3) {
744             u8 *dst8 = (u8 *) dst;
745             u8 __iomem *src8 = (u8 __iomem *) src;
746
747             for (i = c & 3; i--;)
748                 *dst8++ = fb_readb(src8++);
749
750             src = (u32 __iomem *) src8;
751         }
752
753         if (copy_to_user(buf, buffer, c)) {
754             err = -EFAULT;
755             break;
756         }
757         *ppos += c;
758         buf += c;
759         cnt += c;
760         count -= c;
761     }
762
763     kfree(buffer);
764
765     return (err) ? err : cnt;
766 }

一般来说read
write函数都没什么可分析的,read无非就是读取设备文件的一段数据,
对于framebuffer来说,这些数据就保存在虚拟地址info->screen_base,info->screen_base是framebuffer
mem的虚拟地址,info->fix.smem_start是framebuffer
mem的物理地址,正常来说,驱动都是访问info->screen_base。

711~712 framebuffer驱动可以实现特定的read函数,也可以使用通用的实现

read的主体很简单就是通过fb_readl和fb_readb来读取info->screen_base的内容,copy到参数@buf中去

852 int
853 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
854 {
855     struct fb_fix_screeninfo *fix = &info->fix;
856     unsigned int yres = info->var.yres;
857     int err = 0;
858
859     if (var->yoffset > 0) {
860         if (var->vmode & FB_VMODE_YWRAP) {
861             if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
862                 err = -EINVAL;
863             else
864                 yres = 0;
865         } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
866             err = -EINVAL;
867     }
868
869     if (var->xoffset > 0 && (!fix->xpanstep ||
870                  (var->xoffset % fix->xpanstep)))
871         err = -EINVAL;
872
873     if (err || !info->fbops->fb_pan_display ||
874         var->yoffset > info->var.yres_virtual - yres ||
875         var->xoffset > info->var.xres_virtual - info->var.xres)
876         return -EINVAL;
877
878     if ((err = info->fbops->fb_pan_display(var, info)))
879         return err;
880
881     info->var.xoffset = var->xoffset;
882     info->var.yoffset = var->yoffset;
883     if (var->vmode & FB_VMODE_YWRAP)
884         info->var.vmode |= FB_VMODE_YWRAP;
885     else
886         info->var.vmode &= ~FB_VMODE_YWRAP;
887     return 0;
888 }
这个函数是FBIOPAN_DISPLAY的实现,关于FBIOPAN_DISPLAY的用途, linux
kernel对这个定义也非常模糊,网上的说法也是很不确定。我的看法是这个函数用到了var参数的xoffser和yoffset,通过这两个参数可以实现屏幕内容的平滑移动。

这个调用在Android平台上还有个很重要的作用,UI刷屏就是通过FBIOPAN_DISPLAY实现的,可以实现双buffer的切换,防止tear-drop效果。

913 int
914 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
915 {
916     int flags = info->flags;
917     int ret = 0;
918
919     if (var->activate & FB_ACTIVATE_INV_MODE) {
920         struct fb_videomode mode1, mode2;
921
922         fb_var_to_videomode(&mode1, var);
923         fb_var_to_videomode(&mode2, &info->var);
924         /* make sure we don't delete the videomode of current var */
925         ret = fb_mode_is_equal(&mode1, &mode2);
926
927         if (!ret) {
928             struct fb_event event;
929
930             event.info = info;
931             event.data = &mode1;
932             ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
933         }
934
935         if (!ret)
936             fb_delete_videomode(&mode1, &info->modelist);
937
938
939         ret = (ret) ? -EINVAL : 0;
940         goto done;
941     }
942
943     if ((var->activate & FB_ACTIVATE_FORCE) ||
944         memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
945         u32 activate = var->activate;
946
947         if (!info->fbops->fb_check_var) {
948             *var = info->var;
949             goto done;
950         }
951
952         ret = info->fbops->fb_check_var(var, info);
953
954         if (ret)
955             goto done;
956
957         if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
958             struct fb_var_screeninfo old_var;
959             struct fb_videomode mode;
960
961             if (info->fbops->fb_get_caps) {
962                 ret = fb_check_caps(info, var, activate);
963
964                 if (ret)
965                     goto done;
966             }
967
968             old_var = info->var;
969             info->var = *var;
970
971             if (info->fbops->fb_set_par) {
972                 ret = info->fbops->fb_set_par(info);
973
974                 if (ret) {
975                     info->var = old_var;
976                     printk(KERN_WARNING "detected "
977                         "fb_set_par error, "
978                         "error code: %d\n", ret);
979                     goto done;
980                 }
981             }
982
983             fb_pan_display(info, &info->var);
984             fb_set_cmap(&info->cmap, info);
985             fb_var_to_videomode(&mode, &info->var);
986
987             if (info->modelist.prev && info->modelist.next &&
988                 !list_empty(&info->modelist))
989                 ret = fb_add_videomode(&mode, &info->modelist);
990
991             if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
992                 struct fb_event event;
993                 int evnt = (activate & FB_ACTIVATE_ALL) ?
994                     FB_EVENT_MODE_CHANGE_ALL :
995                     FB_EVENT_MODE_CHANGE;
996
997                 info->flags &= ~FBINFO_MISC_USEREVENT;
998                 event.info = info;
999                 event.data = &mode;
1000                 fb_notifier_call_chain(evnt, &event);
1001             }
1002         }
1003     }
1004
1005  done:
1006     return ret;
1007 }

这个函数处理两类情况,

第一种从fb_info->modelist中删除@var对应的mode,

922~923转换var和当前fb_info->var 到viewmode

如果@var对应的viewmode是当前正在使用的viewmode那么调用notifier函数,并从info->modelist中删除所有匹配的viewmode

第二种情况,如果有FB_ACTIVATE_FORCE标记或者新@var不等与fb_info当前的var: fb_info->var

952 一般来说驱动的fb_check_var会check @var参数,并且调整到有效值

957行,如果var->active是FB_ACTIVE_NOW, 那么激活给定的@var

968~972 设置info->var为@var, 并且调用fb_set_par设置新的framebuffer参数,改变操作模式

983 在设置新的framebuffer后需要调用fb_pan_display来更新pan display, fb_pan_display需要特定的framebuffer实现

985~989 把var对应的videomode加入到modelist中去

991~1000 广播framebuffer事件

1009 int
1010 fb_blank(struct fb_info *info, int blank)
1011 {  
1012     int ret = -EINVAL;
1013
1014     if (blank > FB_BLANK_POWERDOWN)
1015         blank = FB_BLANK_POWERDOWN;
1016
1017     if (info->fbops->fb_blank)
1018         ret = info->fbops->fb_blank(blank, info);
1019
1020     if (!ret) {
1021         struct fb_event event;
1022
1023         event.info = info;
1024         event.data = &blank;
1025         fb_notifier_call_chain(FB_EVENT_BLANK, &event);
1026     }
1027
1028     return ret;
1029 }
这个函数调用info->fbops->fb_blank, @blank指定了blank的类型,包括POWERDOWN, NORMAL HSYNC_SUSPEND, VSYNC_SUSPEND

以及重新点亮display, 对于mxc framebuffer驱动, 就是使能/无效 ipu channel

1031 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1032             unsigned long arg)
1033 {
1034     struct fb_ops *fb;
1035     struct fb_var_screeninfo var;
1036     struct fb_fix_screeninfo fix;
1037     struct fb_con2fbmap con2fb;
1038     struct fb_cmap cmap_from;
1039     struct fb_cmap_user cmap;
1040     struct fb_event event;
1041     void __user *argp = (void __user *)arg;
1042     long ret = 0;
1043
1044     switch (cmd) {
1045     case FBIOGET_VSCREENINFO:
1046         if (!lock_fb_info(info))
1047             return -ENODEV;
1048         var = info->var;
1049         unlock_fb_info(info);
1050
1051         ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
1052         break;
1053     case FBIOPUT_VSCREENINFO:
1054         if (copy_from_user(&var, argp, sizeof(var)))
1055             return -EFAULT;
1056         if (!lock_fb_info(info))
1057             return -ENODEV;
1058         acquire_console_sem();
1059         info->flags |= FBINFO_MISC_USEREVENT;
1060         ret = fb_set_var(info, &var);
1061         info->flags &= ~FBINFO_MISC_USEREVENT;
1062         release_console_sem();
1063         unlock_fb_info(info);
1064         if (!ret && copy_to_user(argp, &var, sizeof(var)))
1065             ret = -EFAULT;
1066         break;
1067     case FBIOGET_FSCREENINFO:
1068         if (!lock_fb_info(info))
1069             return -ENODEV;
1070         fix = info->fix;
1071         unlock_fb_info(info);
1072
1073         ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
1074         break;
1075     case FBIOPUTCMAP:
1076         if (copy_from_user(&cmap, argp, sizeof(cmap)))
1077             return -EFAULT;
1078         ret = fb_set_user_cmap(&cmap, info);
1079         break;
1080     case FBIOGETCMAP:
1081         if (copy_from_user(&cmap, argp, sizeof(cmap)))
1082             return -EFAULT;
1083         if (!lock_fb_info(info))
1084             return -ENODEV;
1085         cmap_from = info->cmap;
1086         unlock_fb_info(info);
1087         ret = fb_cmap_to_user(&cmap_from, &cmap);
1088         break;
1089     case FBIOPAN_DISPLAY:
1090         if (copy_from_user(&var, argp, sizeof(var)))
1091             return -EFAULT;
1092         if (!lock_fb_info(info))
1093             return -ENODEV;
1094         acquire_console_sem();
1095         ret = fb_pan_display(info, &var);
1096         release_console_sem();
1097         unlock_fb_info(info);
1098         if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
1099             return -EFAULT;
1100         break;
1101     case FBIO_CURSOR:
1102         ret = -EINVAL;
1103         break;
1104     case FBIOGET_CON2FBMAP:
1105         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
1106             return -EFAULT;
1107         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1108             return -EINVAL;
1109         con2fb.framebuffer = -1;
1110         event.data = &con2fb;
1111         if (!lock_fb_info(info))
1112             return -ENODEV;
1113         event.info = info;
1114         fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
1115         unlock_fb_info(info);
1116         ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
1117         break;
1118     case FBIOPUT_CON2FBMAP:
1119         if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
1120             return -EFAULT;
1121         if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1122             return -EINVAL;
1123         if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
1124             return -EINVAL;
1125         if (!registered_fb[con2fb.framebuffer])
1126             request_module("fb%d", con2fb.framebuffer);
1127         if (!registered_fb[con2fb.framebuffer]) {
1128             ret = -EINVAL;
1129             break;
1130         }
1131         event.data = &con2fb;
1132         if (!lock_fb_info(info))
1133             return -ENODEV;
1134         event.info = info;
1135         ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
1136         unlock_fb_info(info);
1137         break;
1138     case FBIOBLANK:
1139         if (!lock_fb_info(info))
1140             return -ENODEV;
1141         acquire_console_sem();
1142         info->flags |= FBINFO_MISC_USEREVENT;
1143         ret = fb_blank(info, arg);
1144         info->flags &= ~FBINFO_MISC_USEREVENT;
1145         release_console_sem();
1146         unlock_fb_info(info);
1147         break;
1148     default:
1149         if (!lock_fb_info(info))
1150             return -ENODEV;
1151         fb = info->fbops;
1152         if (fb->fb_ioctl)
1153             ret = fb->fb_ioctl(info, cmd, arg);
1154         else
1155             ret = -ENOTTY;
1156         unlock_fb_info(info);
1157     }
1158     return ret;
1159 }
1160

对于这个函数没什么可说的了,介绍下每个ioctl命令的含义

FBIOGET_VSCREENINFO: Used to get the variable screen information of the frame buffer

FBIOPUT_VSCREENINFO: Used to set variable screen parameters for the frame buffer

FBIOGET_FSCREENINFO: Used to get fixiable screen parameters for the frame buffer

FBIOPUTCMAP: 设置framebuffer的color map

FBIOGETCMAP: 获取framebuffer的color map

FBIOPAN_DISPLAY:按照参数var->xoffset 和var->yoffset平移frame buffer中的内容, 可以用在双buffer的切换

FBIOGET_CON2FBMAP和FBIOPUT_CON2FBMAP实在没看明白什么意思

FBIOBLANK:使能或者点亮frame buffer, 参数arg可以是POWERDOWN, NORMAL HSYNC_SUSPEND, VSYNC_SUSPEND UNBLANK

1323 fb_mmap(struct file *file, struct vm_area_struct * vma)
1324 {
1325     int fbidx = iminor(file->f_path.dentry->d_inode);
1326     struct fb_info *info = registered_fb[fbidx];
1327     struct fb_ops *fb = info->fbops;
1328     unsigned long off;
1329     unsigned long start;
1330     u32 len;
1331
1332     if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1333         return -EINVAL;
1334     off = vma->vm_pgoff << PAGE_SHIFT;
1335     if (!fb)
1336         return -ENODEV;
1337     mutex_lock(&info->mm_lock);
1338     if (fb->fb_mmap) {
1339         int res;
1340         res = fb->fb_mmap(info, vma);
1341         mutex_unlock(&info->mm_lock);
1342         return res;
1343     }
1344
1345     /* frame buffer memory */
1346     start = info->fix.smem_start;
1347     len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
1348     if (off >= len) {
1349         /* memory mapped io */
1350         off -= len;
1351         if (info->var.accel_flags) {
1352             mutex_unlock(&info->mm_lock);
1353             return -EINVAL;
1354         }
1355         start = info->fix.mmio_start;
1356         len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
1357     }
1358     mutex_unlock(&info->mm_lock);
1359     start &= PAGE_MASK;
1360     if ((vma->vm_end - vma->vm_start + off) > len)
1361         return -EINVAL;
1362     off += start;
1363     vma->vm_pgoff = off >> PAGE_SHIFT;
1364     /* This is an IO map - tell maydump to skip this VMA */
1365     vma->vm_flags |= VM_IO | VM_RESERVED;
1366     fb_pgprotect(file, vma, off);
1367     if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1368                  vma->vm_end - vma->vm_start, vma->vm_page_prot))
1369         return -EAGAIN;
1370     return 0;
1371 }

man mmap可以知道mmap的作用是映射文件或设备到内存中,因此fb_mmap的作用就是把framebuffer的物理内存映射到进程的虚拟地址空间。

1334     off = vma->vm_pgoff << PAGE_SHIFT; off是这个vm area对应的文件偏移

1346 fix.smem_start是frame buffer的起始物理地址

1367~1368应该是映射为物理地址到vm area中

1546 int
1547 register_framebuffer(struct fb_info *fb_info)
1548 {
1549     int i;
1550     struct fb_event event;
1551     struct fb_videomode mode;
1552
1553     if (num_registered_fb == FB_MAX)
1554         return -ENXIO;
1555
1556     if (fb_check_foreignness(fb_info))
1557         return -ENOSYS;
1558
1559     remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
1560                      fb_is_primary_device(fb_info));
1561
1562     num_registered_fb++;
1563     for (i = 0 ; i < FB_MAX; i++)
1564         if (!registered_fb[i])
1565             break;
1566     fb_info->node = i;
1567     mutex_init(&fb_info->lock);
1568     mutex_init(&fb_info->mm_lock);
1569
1570     fb_info->dev = device_create(fb_class, fb_info->device,
1571                      MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
1572     if (IS_ERR(fb_info->dev)) {
1573         /* Not fatal */
1574         printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
1575         fb_info->dev = NULL;
1576     } else
1577         fb_init_device(fb_info);
1578
1579     if (fb_info->pixmap.addr == NULL) {
1580         fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
1581         if (fb_info->pixmap.addr) {
1582             fb_info->pixmap.size = FBPIXMAPSIZE;
1583             fb_info->pixmap.buf_align = 1;
1584             fb_info->pixmap.scan_align = 1;
1585             fb_info->pixmap.access_align = 32;
1586             fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
1587         }
1588     }
1589     fb_info->pixmap.offset = 0;
1590
1591     if (!fb_info->pixmap.blit_x)
1592         fb_info->pixmap.blit_x = ~(u32)0;
1593
1594     if (!fb_info->pixmap.blit_y)
1595         fb_info->pixmap.blit_y = ~(u32)0;
1596
1597     if (!fb_info->modelist.prev || !fb_info->modelist.next)
1598         INIT_LIST_HEAD(&fb_info->modelist);
1599
1600     fb_var_to_videomode(&mode, &fb_info->var);
1601     fb_add_videomode(&mode, &fb_info->modelist);
1602     registered_fb[i] = fb_info;
1603
1604     event.info = fb_info;
1605     if (!lock_fb_info(fb_info))
1606         return -ENODEV;
1607     fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1608     unlock_fb_info(fb_info);
1609     return 0;
1610 }
这个函数为framebuffer 驱动提供了注册一个framebuffer device的接口,该函数会把@fb_info加到registered_fb中去

1570 ~1571 为frame buffer设备创建class device name

1577 fb_init_device创建frame buffer的attr文件

pixmap不知道什么意思

1600~1601 转换fb_info->var为 videomode,然后把videomode加入到modelist中

1602 把@fb_info加到registered_fb数组中

1630 int
1631 unregister_framebuffer(struct fb_info *fb_info)
1632 {
1633     struct fb_event event;
1634     int i, ret = 0;
1635
1636     i = fb_info->node;
1637     if (!registered_fb[i]) {
1638         ret = -EINVAL;
1639         goto done;
1640     }
1641
1642
1643     if (!lock_fb_info(fb_info))
1644         return -ENODEV;
1645     event.info = fb_info;
1646     ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
1647     unlock_fb_info(fb_info);
1648
1649     if (ret) {
1650         ret = -EINVAL;
1651         goto done;
1652     }
1653
1654     if (fb_info->pixmap.addr &&
1655         (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
1656         kfree(fb_info->pixmap.addr);
1657     fb_destroy_modelist(&fb_info->modelist);
1658     registered_fb[i]=NULL;
1659     num_registered_fb--;
1660     fb_cleanup_device(fb_info);
1661     device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1662     event.info = fb_info;
1663     fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1664
1665     /* this may free fb info */
1666     if (fb_info->fbops->fb_destroy)
1667         fb_info->fbops->fb_destroy(fb_info);
1668 done:
1669     return ret;
1670 }
unregister_framebuffer实在没什么可看的了

1740 int fb_new_modelist(struct fb_info *info)
1741 {
1742     struct fb_event event;
1743     struct fb_var_screeninfo var = info->var;
1744     struct list_head *pos, *n;
1745     struct fb_modelist *modelist;
1746     struct fb_videomode *m, mode;
1747     int err = 1;
1748
1749     list_for_each_safe(pos, n, &info->modelist) {
1750         modelist = list_entry(pos, struct fb_modelist, list);
1751         m = &modelist->mode;
1752         fb_videomode_to_var(&var, m);
1753         var.activate = FB_ACTIVATE_TEST;
1754         err = fb_set_var(info, &var);
1755         fb_var_to_videomode(&mode, &var);
1756         if (err || !fb_mode_is_equal(m, &mode)) {
1757             list_del(pos);
1758             kfree(pos);
1759         }
1760     }
1761
1762     err = 1;
1763
1764     if (!list_empty(&info->modelist)) {
1765         if (!lock_fb_info(info))
1766             return -ENODEV;
1767         event.info = info;
1768         err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
1769         unlock_fb_info(info);
1770     }
1771
1772     return err;
1773 }
测试info->modelist中的每一个mode,从这个modelist中删除无效的mode节点

1787 int fb_get_options(char *name, char **option)
1788 {
1789     char *opt, *options = NULL;
1790     int opt_len, retval = 0;
1791     int name_len = strlen(name), i;
1792
1793     if (name_len && ofonly && strncmp(name, "offb", 4))
1794         retval = 1;
1795
1796     if (name_len && !retval) {
1797         for (i = 0; i < FB_MAX; i++) {
1798             if (video_options[i] == NULL)
1799                 continue;
1800             opt_len = strlen(video_options[i]);
1801             if (!opt_len)
1802                 continue;
1803             opt = video_options[i];
1804             if (!strncmp(name, opt, name_len) &&
1805                 opt[name_len] == ':')
1806                 options = opt + name_len + 1;
1807         }
1808     }
1809     if (options && !strncmp(options, "off", 3))
1810         retval = 1;
1811
1812     if (option)
1813         *option = options;
1814
1815     return retval;
1816 }

从kernel cmd 参数中提取framebuffer相关的选项

Frame buffer分析 - fbmem.c【转】的更多相关文章

  1. Android系统Surface机制的SurfaceFlinger服务对帧缓冲区(Frame Buffer)的管理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8046659 在前文中,我们分析了Surface ...

  2. frame buffer简单应用

    现在我们要在LCD上画一个点,我们无法直接对LCD屏进行操作.这时候就需要用到FrameBuffer,Linux可以FrameBuffer这个设备来供用户态进程实现直接写屏.首先我们先简单看一下lin ...

  3. 关于缓冲的认识---Frame Buffer

    关于缓冲的认识---Frame Buffer 重点来了:

  4. Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析[转]

    前面在介绍Android系统的开机画面时提到,Android设备的显示屏被抽象为一个帧缓冲区,而Android系统中的SurfaceFlinger服务就是通过向这个帧缓冲区写入内容来绘制应用程序的用户 ...

  5. 【OpenGL】OpenGL帧缓存对象(FBO:Frame Buffer Object) 【转】

    http://blog.csdn.net/xiajun07061225/article/details/7283929/ OpenGL Frame BufferObject(FBO) Overview ...

  6. libevent中数据缓冲区buffer分析

    很多时候为了应对数据IO的"慢"或者其他原因都需要使用数据缓冲区.对于数据缓冲,我们不陌生,但是对于如何实现这个缓冲区,相信很多时候大家都没有考虑过.今天就通过分析libevent ...

  7. OpenGL帧缓存对象(FBO:Frame Buffer Object)(转载)

    原文地址http://www.songho.ca/opengl/gl_fbo.html 但有改动. OpenGL Frame BufferObject(FBO) Overview: 在OpenGL渲染 ...

  8. OpenGL帧缓存对象(FBO:Frame Buffer Object)

    http://blog.csdn.net/dreamcs/article/details/7691690 转http://blog.csdn.net/xiajun07061225/article/de ...

  9. OpenGL帧缓存对象(FBO:Frame Buffer Object) 【转】

    http://blog.csdn.net/dreamcs/article/details/7691690 原文地址http://www.songho.ca/opengl/gl_fbo.html 但有改 ...

随机推荐

  1. Java 后端微信小程序支付demo (网上说的坑里面基本上都有)

    Java 后端微信小程序支付 一.遇到的问题 1. 商户号该产品权限未开通,请前往商户平台>产品中心检查后重试 2.签名错误 3.已经调起微信统一下单接口,可以拿到预支付ID,但是前端支付的时候 ...

  2. 最短路算法模板SPFA、disjkstra、Floyd

    朴素SPFA(链表建边) #include <iostream> #include <cstdio> #include <cstring> #include < ...

  3. 从一次输入框无法输入的bug,谈如何限制输入框输入类型

    bug的产生和修改 上周临近周末休息的时候,一个同事跑过来了,对我说:"阿伦啊,有一个页面出问题了,火狐浏览器所有的input都没法输入了."我一听,是不是你给加了什么属性,让in ...

  4. day-4 python多进程编程知识点汇总

    1. python多进程简介 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心.Python提供了非常好用的多进程包multiprocessing,他提供了一 ...

  5. C语言头文件引用

    1,引用分为两种 firs:include<fileName.h> 引用系统头文件一般用<>. second:include"fileName.h" 引用自 ...

  6. shuffle和sort分析

    MapReduce中的Shuffle和Sort分析 MapReduce 是现今一个非常流行的分布式计算框架,它被设计用于并行计算海量数据.第一个提出该技术框架的是Google 公司,而Google 的 ...

  7. CentOS ping www.baidu.com 报错 name or service not know

    今天尝试安装了centos系统 玩一玩 刚刚装好的操作系统 ping www.baidu.com的时候  报出 name or service not known 查了好多资料,都没有很好的解决 最后 ...

  8. RxJava系列7(最佳实践)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  9. SpringMVC(八):使用Servlet原生API作为Spring MVC hanlder方法的参数

    在SpringMVC开发中,是有场景需要在Handler方法中直接使用ServletAPI. 在Spring MVC Handler的方法中都支持哪些Servlet API作为参数呢? --Respo ...

  10. easygui的导入方式

    方法一: >>> import easygui >>> easygui.msgbox('hello') 方法二: >>> from easygui ...