This source file includes following definitions.
- get_fb_info
- put_fb_info
- fb_get_color_depth
- fb_pad_aligned_buffer
- fb_pad_unaligned_buffer
- fb_get_buffer_offset
- safe_shift
- fb_set_logocmap
- fb_set_logo_truepalette
- fb_set_logo_directpalette
- fb_set_logo
- fb_rotate_logo_ud
- fb_rotate_logo_cw
- fb_rotate_logo_ccw
- fb_rotate_logo
- fb_do_show_logo
- fb_show_logo_line
- fb_append_extra_logo
- fb_prepare_extra_logos
- fb_show_extra_logos
- fb_prepare_extra_logos
- fb_show_extra_logos
- fb_prepare_logo
- fb_show_logo
- fb_prepare_logo
- fb_show_logo
- fb_seq_start
- fb_seq_next
- fb_seq_stop
- fb_seq_show
- file_fb_info
- fb_read
- fb_write
- fb_pan_display
- fb_check_caps
- fb_set_var
- fb_blank
- do_fb_ioctl
- fb_ioctl
- fb_getput_cmap
- do_fscreeninfo_to_user
- fb_get_fscreeninfo
- fb_compat_ioctl
- fb_mmap
- fb_open
- fb_release
- get_fb_unmapped_area
- fb_check_foreignness
- apertures_overlap
- fb_do_apertures_overlap
- do_remove_conflicting_framebuffers
- do_register_framebuffer
- unbind_console
- unlink_framebuffer
- do_unregister_framebuffer
- remove_conflicting_framebuffers
- remove_conflicting_pci_framebuffers
- register_framebuffer
- unregister_framebuffer
- fb_set_suspend
- fbmem_init
- fbmem_exit
- fb_new_modelist
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <linux/module.h>
15
16 #include <linux/compat.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <linux/kernel.h>
20 #include <linux/major.h>
21 #include <linux/slab.h>
22 #include <linux/mm.h>
23 #include <linux/mman.h>
24 #include <linux/vt.h>
25 #include <linux/init.h>
26 #include <linux/linux_logo.h>
27 #include <linux/proc_fs.h>
28 #include <linux/seq_file.h>
29 #include <linux/console.h>
30 #include <linux/kmod.h>
31 #include <linux/err.h>
32 #include <linux/device.h>
33 #include <linux/efi.h>
34 #include <linux/fb.h>
35 #include <linux/fbcon.h>
36 #include <linux/mem_encrypt.h>
37 #include <linux/pci.h>
38
39 #include <asm/fb.h>
40
41
42
43
44
45
46 #define FBPIXMAPSIZE (1024 * 8)
47
48 static DEFINE_MUTEX(registration_lock);
49
50 struct fb_info *registered_fb[FB_MAX] __read_mostly;
51 EXPORT_SYMBOL(registered_fb);
52
53 int num_registered_fb __read_mostly;
54 EXPORT_SYMBOL(num_registered_fb);
55
56 bool fb_center_logo __read_mostly;
57 EXPORT_SYMBOL(fb_center_logo);
58
59 static struct fb_info *get_fb_info(unsigned int idx)
60 {
61 struct fb_info *fb_info;
62
63 if (idx >= FB_MAX)
64 return ERR_PTR(-ENODEV);
65
66 mutex_lock(®istration_lock);
67 fb_info = registered_fb[idx];
68 if (fb_info)
69 atomic_inc(&fb_info->count);
70 mutex_unlock(®istration_lock);
71
72 return fb_info;
73 }
74
75 static void put_fb_info(struct fb_info *fb_info)
76 {
77 if (!atomic_dec_and_test(&fb_info->count))
78 return;
79 if (fb_info->fbops->fb_destroy)
80 fb_info->fbops->fb_destroy(fb_info);
81 }
82
83
84
85
86
87 int fb_get_color_depth(struct fb_var_screeninfo *var,
88 struct fb_fix_screeninfo *fix)
89 {
90 int depth = 0;
91
92 if (fix->visual == FB_VISUAL_MONO01 ||
93 fix->visual == FB_VISUAL_MONO10)
94 depth = 1;
95 else {
96 if (var->green.length == var->blue.length &&
97 var->green.length == var->red.length &&
98 var->green.offset == var->blue.offset &&
99 var->green.offset == var->red.offset)
100 depth = var->green.length;
101 else
102 depth = var->green.length + var->red.length +
103 var->blue.length;
104 }
105
106 return depth;
107 }
108 EXPORT_SYMBOL(fb_get_color_depth);
109
110
111
112
113 void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
114 {
115 __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
116 }
117 EXPORT_SYMBOL(fb_pad_aligned_buffer);
118
119 void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
120 u32 shift_high, u32 shift_low, u32 mod)
121 {
122 u8 mask = (u8) (0xfff << shift_high), tmp;
123 int i, j;
124
125 for (i = height; i--; ) {
126 for (j = 0; j < idx; j++) {
127 tmp = dst[j];
128 tmp &= mask;
129 tmp |= *src >> shift_low;
130 dst[j] = tmp;
131 tmp = *src << shift_high;
132 dst[j+1] = tmp;
133 src++;
134 }
135 tmp = dst[idx];
136 tmp &= mask;
137 tmp |= *src >> shift_low;
138 dst[idx] = tmp;
139 if (shift_high < mod) {
140 tmp = *src << shift_high;
141 dst[idx+1] = tmp;
142 }
143 src++;
144 dst += d_pitch;
145 }
146 }
147 EXPORT_SYMBOL(fb_pad_unaligned_buffer);
148
149
150
151
152
153 char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
154 {
155 u32 align = buf->buf_align - 1, offset;
156 char *addr = buf->addr;
157
158
159
160
161 if (buf->flags & FB_PIXMAP_IO) {
162 if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
163 info->fbops->fb_sync(info);
164 return addr;
165 }
166
167
168 offset = buf->offset + align;
169 offset &= ~align;
170 if (offset + size > buf->size) {
171
172
173
174
175 if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
176 info->fbops->fb_sync(info);
177 offset = 0;
178 }
179 buf->offset = offset + size;
180 addr += offset;
181
182 return addr;
183 }
184 EXPORT_SYMBOL(fb_get_buffer_offset);
185
186 #ifdef CONFIG_LOGO
187
188 static inline unsigned safe_shift(unsigned d, int n)
189 {
190 return n < 0 ? d >> -n : d << n;
191 }
192
193 static void fb_set_logocmap(struct fb_info *info,
194 const struct linux_logo *logo)
195 {
196 struct fb_cmap palette_cmap;
197 u16 palette_green[16];
198 u16 palette_blue[16];
199 u16 palette_red[16];
200 int i, j, n;
201 const unsigned char *clut = logo->clut;
202
203 palette_cmap.start = 0;
204 palette_cmap.len = 16;
205 palette_cmap.red = palette_red;
206 palette_cmap.green = palette_green;
207 palette_cmap.blue = palette_blue;
208 palette_cmap.transp = NULL;
209
210 for (i = 0; i < logo->clutsize; i += n) {
211 n = logo->clutsize - i;
212
213 if (n > 16)
214 n = 16;
215 palette_cmap.start = 32 + i;
216 palette_cmap.len = n;
217 for (j = 0; j < n; ++j) {
218 palette_cmap.red[j] = clut[0] << 8 | clut[0];
219 palette_cmap.green[j] = clut[1] << 8 | clut[1];
220 palette_cmap.blue[j] = clut[2] << 8 | clut[2];
221 clut += 3;
222 }
223 fb_set_cmap(&palette_cmap, info);
224 }
225 }
226
227 static void fb_set_logo_truepalette(struct fb_info *info,
228 const struct linux_logo *logo,
229 u32 *palette)
230 {
231 static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
232 unsigned char redmask, greenmask, bluemask;
233 int redshift, greenshift, blueshift;
234 int i;
235 const unsigned char *clut = logo->clut;
236
237
238
239
240
241
242 redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8];
243 greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
244 bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8];
245 redshift = info->var.red.offset - (8 - info->var.red.length);
246 greenshift = info->var.green.offset - (8 - info->var.green.length);
247 blueshift = info->var.blue.offset - (8 - info->var.blue.length);
248
249 for ( i = 0; i < logo->clutsize; i++) {
250 palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
251 safe_shift((clut[1] & greenmask), greenshift) |
252 safe_shift((clut[2] & bluemask), blueshift));
253 clut += 3;
254 }
255 }
256
257 static void fb_set_logo_directpalette(struct fb_info *info,
258 const struct linux_logo *logo,
259 u32 *palette)
260 {
261 int redshift, greenshift, blueshift;
262 int i;
263
264 redshift = info->var.red.offset;
265 greenshift = info->var.green.offset;
266 blueshift = info->var.blue.offset;
267
268 for (i = 32; i < 32 + logo->clutsize; i++)
269 palette[i] = i << redshift | i << greenshift | i << blueshift;
270 }
271
272 static void fb_set_logo(struct fb_info *info,
273 const struct linux_logo *logo, u8 *dst,
274 int depth)
275 {
276 int i, j, k;
277 const u8 *src = logo->data;
278 u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
279 u8 fg = 1, d;
280
281 switch (fb_get_color_depth(&info->var, &info->fix)) {
282 case 1:
283 fg = 1;
284 break;
285 case 2:
286 fg = 3;
287 break;
288 default:
289 fg = 7;
290 break;
291 }
292
293 if (info->fix.visual == FB_VISUAL_MONO01 ||
294 info->fix.visual == FB_VISUAL_MONO10)
295 fg = ~((u8) (0xfff << info->var.green.length));
296
297 switch (depth) {
298 case 4:
299 for (i = 0; i < logo->height; i++)
300 for (j = 0; j < logo->width; src++) {
301 *dst++ = *src >> 4;
302 j++;
303 if (j < logo->width) {
304 *dst++ = *src & 0x0f;
305 j++;
306 }
307 }
308 break;
309 case 1:
310 for (i = 0; i < logo->height; i++) {
311 for (j = 0; j < logo->width; src++) {
312 d = *src ^ xor;
313 for (k = 7; k >= 0 && j < logo->width; k--) {
314 *dst++ = ((d >> k) & 1) ? fg : 0;
315 j++;
316 }
317 }
318 }
319 break;
320 }
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349 static struct logo_data {
350 int depth;
351 int needs_directpalette;
352 int needs_truepalette;
353 int needs_cmapreset;
354 const struct linux_logo *logo;
355 } fb_logo __read_mostly;
356
357 static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
358 {
359 u32 size = width * height, i;
360
361 out += size - 1;
362
363 for (i = size; i--; )
364 *out-- = *in++;
365 }
366
367 static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
368 {
369 int i, j, h = height - 1;
370
371 for (i = 0; i < height; i++)
372 for (j = 0; j < width; j++)
373 out[height * j + h - i] = *in++;
374 }
375
376 static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
377 {
378 int i, j, w = width - 1;
379
380 for (i = 0; i < height; i++)
381 for (j = 0; j < width; j++)
382 out[height * (w - j) + i] = *in++;
383 }
384
385 static void fb_rotate_logo(struct fb_info *info, u8 *dst,
386 struct fb_image *image, int rotate)
387 {
388 u32 tmp;
389
390 if (rotate == FB_ROTATE_UD) {
391 fb_rotate_logo_ud(image->data, dst, image->width,
392 image->height);
393 image->dx = info->var.xres - image->width - image->dx;
394 image->dy = info->var.yres - image->height - image->dy;
395 } else if (rotate == FB_ROTATE_CW) {
396 fb_rotate_logo_cw(image->data, dst, image->width,
397 image->height);
398 tmp = image->width;
399 image->width = image->height;
400 image->height = tmp;
401 tmp = image->dy;
402 image->dy = image->dx;
403 image->dx = info->var.xres - image->width - tmp;
404 } else if (rotate == FB_ROTATE_CCW) {
405 fb_rotate_logo_ccw(image->data, dst, image->width,
406 image->height);
407 tmp = image->width;
408 image->width = image->height;
409 image->height = tmp;
410 tmp = image->dx;
411 image->dx = image->dy;
412 image->dy = info->var.yres - image->height - tmp;
413 }
414
415 image->data = dst;
416 }
417
418 static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
419 int rotate, unsigned int num)
420 {
421 unsigned int x;
422
423 if (image->width > info->var.xres || image->height > info->var.yres)
424 return;
425
426 if (rotate == FB_ROTATE_UR) {
427 for (x = 0;
428 x < num && image->dx + image->width <= info->var.xres;
429 x++) {
430 info->fbops->fb_imageblit(info, image);
431 image->dx += image->width + 8;
432 }
433 } else if (rotate == FB_ROTATE_UD) {
434 u32 dx = image->dx;
435
436 for (x = 0; x < num && image->dx <= dx; x++) {
437 info->fbops->fb_imageblit(info, image);
438 image->dx -= image->width + 8;
439 }
440 } else if (rotate == FB_ROTATE_CW) {
441 for (x = 0;
442 x < num && image->dy + image->height <= info->var.yres;
443 x++) {
444 info->fbops->fb_imageblit(info, image);
445 image->dy += image->height + 8;
446 }
447 } else if (rotate == FB_ROTATE_CCW) {
448 u32 dy = image->dy;
449
450 for (x = 0; x < num && image->dy <= dy; x++) {
451 info->fbops->fb_imageblit(info, image);
452 image->dy -= image->height + 8;
453 }
454 }
455 }
456
457 static int fb_show_logo_line(struct fb_info *info, int rotate,
458 const struct linux_logo *logo, int y,
459 unsigned int n)
460 {
461 u32 *palette = NULL, *saved_pseudo_palette = NULL;
462 unsigned char *logo_new = NULL, *logo_rotate = NULL;
463 struct fb_image image;
464
465
466 if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
467 info->fbops->owner)
468 return 0;
469
470 image.depth = 8;
471 image.data = logo->data;
472
473 if (fb_logo.needs_cmapreset)
474 fb_set_logocmap(info, logo);
475
476 if (fb_logo.needs_truepalette ||
477 fb_logo.needs_directpalette) {
478 palette = kmalloc(256 * 4, GFP_KERNEL);
479 if (palette == NULL)
480 return 0;
481
482 if (fb_logo.needs_truepalette)
483 fb_set_logo_truepalette(info, logo, palette);
484 else
485 fb_set_logo_directpalette(info, logo, palette);
486
487 saved_pseudo_palette = info->pseudo_palette;
488 info->pseudo_palette = palette;
489 }
490
491 if (fb_logo.depth <= 4) {
492 logo_new = kmalloc_array(logo->width, logo->height,
493 GFP_KERNEL);
494 if (logo_new == NULL) {
495 kfree(palette);
496 if (saved_pseudo_palette)
497 info->pseudo_palette = saved_pseudo_palette;
498 return 0;
499 }
500 image.data = logo_new;
501 fb_set_logo(info, logo, logo_new, fb_logo.depth);
502 }
503
504 if (fb_center_logo) {
505 int xres = info->var.xres;
506 int yres = info->var.yres;
507
508 if (rotate == FB_ROTATE_CW || rotate == FB_ROTATE_CCW) {
509 xres = info->var.yres;
510 yres = info->var.xres;
511 }
512
513 while (n && (n * (logo->width + 8) - 8 > xres))
514 --n;
515 image.dx = (xres - n * (logo->width + 8) - 8) / 2;
516 image.dy = y ?: (yres - logo->height) / 2;
517 } else {
518 image.dx = 0;
519 image.dy = y;
520 }
521
522 image.width = logo->width;
523 image.height = logo->height;
524
525 if (rotate) {
526 logo_rotate = kmalloc_array(logo->width, logo->height,
527 GFP_KERNEL);
528 if (logo_rotate)
529 fb_rotate_logo(info, logo_rotate, &image, rotate);
530 }
531
532 fb_do_show_logo(info, &image, rotate, n);
533
534 kfree(palette);
535 if (saved_pseudo_palette != NULL)
536 info->pseudo_palette = saved_pseudo_palette;
537 kfree(logo_new);
538 kfree(logo_rotate);
539 return image.dy + logo->height;
540 }
541
542
543 #ifdef CONFIG_FB_LOGO_EXTRA
544
545 #define FB_LOGO_EX_NUM_MAX 10
546 static struct logo_data_extra {
547 const struct linux_logo *logo;
548 unsigned int n;
549 } fb_logo_ex[FB_LOGO_EX_NUM_MAX];
550 static unsigned int fb_logo_ex_num;
551
552 void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
553 {
554 if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
555 return;
556
557 fb_logo_ex[fb_logo_ex_num].logo = logo;
558 fb_logo_ex[fb_logo_ex_num].n = n;
559 fb_logo_ex_num++;
560 }
561
562 static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
563 unsigned int yres)
564 {
565 unsigned int i;
566
567
568 if (info->fix.visual != FB_VISUAL_TRUECOLOR)
569 fb_logo_ex_num = 0;
570
571 for (i = 0; i < fb_logo_ex_num; i++) {
572 if (fb_logo_ex[i].logo->type != fb_logo.logo->type) {
573 fb_logo_ex[i].logo = NULL;
574 continue;
575 }
576 height += fb_logo_ex[i].logo->height;
577 if (height > yres) {
578 height -= fb_logo_ex[i].logo->height;
579 fb_logo_ex_num = i;
580 break;
581 }
582 }
583 return height;
584 }
585
586 static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
587 {
588 unsigned int i;
589
590 for (i = 0; i < fb_logo_ex_num; i++)
591 y = fb_show_logo_line(info, rotate,
592 fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
593
594 return y;
595 }
596
597 #else
598
599 static inline int fb_prepare_extra_logos(struct fb_info *info,
600 unsigned int height,
601 unsigned int yres)
602 {
603 return height;
604 }
605
606 static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
607 {
608 return y;
609 }
610
611 #endif
612
613
614 int fb_prepare_logo(struct fb_info *info, int rotate)
615 {
616 int depth = fb_get_color_depth(&info->var, &info->fix);
617 unsigned int yres;
618 int height;
619
620 memset(&fb_logo, 0, sizeof(struct logo_data));
621
622 if (info->flags & FBINFO_MISC_TILEBLITTING ||
623 info->fbops->owner)
624 return 0;
625
626 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
627 depth = info->var.blue.length;
628 if (info->var.red.length < depth)
629 depth = info->var.red.length;
630 if (info->var.green.length < depth)
631 depth = info->var.green.length;
632 }
633
634 if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
635
636 depth = 4;
637 }
638
639
640 fb_logo.logo = fb_find_logo(depth);
641
642 if (!fb_logo.logo) {
643 return 0;
644 }
645
646 if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
647 yres = info->var.yres;
648 else
649 yres = info->var.xres;
650
651 if (fb_logo.logo->height > yres) {
652 fb_logo.logo = NULL;
653 return 0;
654 }
655
656
657 if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
658 fb_logo.depth = 8;
659 else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
660 fb_logo.depth = 4;
661 else
662 fb_logo.depth = 1;
663
664
665 if (fb_logo.depth > 4 && depth > 4) {
666 switch (info->fix.visual) {
667 case FB_VISUAL_TRUECOLOR:
668 fb_logo.needs_truepalette = 1;
669 break;
670 case FB_VISUAL_DIRECTCOLOR:
671 fb_logo.needs_directpalette = 1;
672 fb_logo.needs_cmapreset = 1;
673 break;
674 case FB_VISUAL_PSEUDOCOLOR:
675 fb_logo.needs_cmapreset = 1;
676 break;
677 }
678 }
679
680 height = fb_logo.logo->height;
681 if (fb_center_logo)
682 height += (yres - fb_logo.logo->height) / 2;
683
684 return fb_prepare_extra_logos(info, height, yres);
685 }
686
687 int fb_show_logo(struct fb_info *info, int rotate)
688 {
689 int y;
690
691 y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
692 num_online_cpus());
693 y = fb_show_extra_logos(info, y, rotate);
694
695 return y;
696 }
697 #else
698 int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
699 int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
700 #endif
701 EXPORT_SYMBOL(fb_prepare_logo);
702 EXPORT_SYMBOL(fb_show_logo);
703
704 static void *fb_seq_start(struct seq_file *m, loff_t *pos)
705 {
706 mutex_lock(®istration_lock);
707 return (*pos < FB_MAX) ? pos : NULL;
708 }
709
710 static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
711 {
712 (*pos)++;
713 return (*pos < FB_MAX) ? pos : NULL;
714 }
715
716 static void fb_seq_stop(struct seq_file *m, void *v)
717 {
718 mutex_unlock(®istration_lock);
719 }
720
721 static int fb_seq_show(struct seq_file *m, void *v)
722 {
723 int i = *(loff_t *)v;
724 struct fb_info *fi = registered_fb[i];
725
726 if (fi)
727 seq_printf(m, "%d %s\n", fi->node, fi->fix.id);
728 return 0;
729 }
730
731 static const struct seq_operations proc_fb_seq_ops = {
732 .start = fb_seq_start,
733 .next = fb_seq_next,
734 .stop = fb_seq_stop,
735 .show = fb_seq_show,
736 };
737
738
739
740
741
742
743
744
745
746 static struct fb_info *file_fb_info(struct file *file)
747 {
748 struct inode *inode = file_inode(file);
749 int fbidx = iminor(inode);
750 struct fb_info *info = registered_fb[fbidx];
751
752 if (info != file->private_data)
753 info = NULL;
754 return info;
755 }
756
757 static ssize_t
758 fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
759 {
760 unsigned long p = *ppos;
761 struct fb_info *info = file_fb_info(file);
762 u8 *buffer, *dst;
763 u8 __iomem *src;
764 int c, cnt = 0, err = 0;
765 unsigned long total_size;
766
767 if (!info || ! info->screen_base)
768 return -ENODEV;
769
770 if (info->state != FBINFO_STATE_RUNNING)
771 return -EPERM;
772
773 if (info->fbops->fb_read)
774 return info->fbops->fb_read(info, buf, count, ppos);
775
776 total_size = info->screen_size;
777
778 if (total_size == 0)
779 total_size = info->fix.smem_len;
780
781 if (p >= total_size)
782 return 0;
783
784 if (count >= total_size)
785 count = total_size;
786
787 if (count + p > total_size)
788 count = total_size - p;
789
790 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
791 GFP_KERNEL);
792 if (!buffer)
793 return -ENOMEM;
794
795 src = (u8 __iomem *) (info->screen_base + p);
796
797 if (info->fbops->fb_sync)
798 info->fbops->fb_sync(info);
799
800 while (count) {
801 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
802 dst = buffer;
803 fb_memcpy_fromfb(dst, src, c);
804 dst += c;
805 src += c;
806
807 if (copy_to_user(buf, buffer, c)) {
808 err = -EFAULT;
809 break;
810 }
811 *ppos += c;
812 buf += c;
813 cnt += c;
814 count -= c;
815 }
816
817 kfree(buffer);
818
819 return (err) ? err : cnt;
820 }
821
822 static ssize_t
823 fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
824 {
825 unsigned long p = *ppos;
826 struct fb_info *info = file_fb_info(file);
827 u8 *buffer, *src;
828 u8 __iomem *dst;
829 int c, cnt = 0, err = 0;
830 unsigned long total_size;
831
832 if (!info || !info->screen_base)
833 return -ENODEV;
834
835 if (info->state != FBINFO_STATE_RUNNING)
836 return -EPERM;
837
838 if (info->fbops->fb_write)
839 return info->fbops->fb_write(info, buf, count, ppos);
840
841 total_size = info->screen_size;
842
843 if (total_size == 0)
844 total_size = info->fix.smem_len;
845
846 if (p > total_size)
847 return -EFBIG;
848
849 if (count > total_size) {
850 err = -EFBIG;
851 count = total_size;
852 }
853
854 if (count + p > total_size) {
855 if (!err)
856 err = -ENOSPC;
857
858 count = total_size - p;
859 }
860
861 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
862 GFP_KERNEL);
863 if (!buffer)
864 return -ENOMEM;
865
866 dst = (u8 __iomem *) (info->screen_base + p);
867
868 if (info->fbops->fb_sync)
869 info->fbops->fb_sync(info);
870
871 while (count) {
872 c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
873 src = buffer;
874
875 if (copy_from_user(src, buf, c)) {
876 err = -EFAULT;
877 break;
878 }
879
880 fb_memcpy_tofb(dst, src, c);
881 dst += c;
882 src += c;
883 *ppos += c;
884 buf += c;
885 cnt += c;
886 count -= c;
887 }
888
889 kfree(buffer);
890
891 return (cnt) ? cnt : err;
892 }
893
894 int
895 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
896 {
897 struct fb_fix_screeninfo *fix = &info->fix;
898 unsigned int yres = info->var.yres;
899 int err = 0;
900
901 if (var->yoffset > 0) {
902 if (var->vmode & FB_VMODE_YWRAP) {
903 if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
904 err = -EINVAL;
905 else
906 yres = 0;
907 } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
908 err = -EINVAL;
909 }
910
911 if (var->xoffset > 0 && (!fix->xpanstep ||
912 (var->xoffset % fix->xpanstep)))
913 err = -EINVAL;
914
915 if (err || !info->fbops->fb_pan_display ||
916 var->yoffset > info->var.yres_virtual - yres ||
917 var->xoffset > info->var.xres_virtual - info->var.xres)
918 return -EINVAL;
919
920 if ((err = info->fbops->fb_pan_display(var, info)))
921 return err;
922 info->var.xoffset = var->xoffset;
923 info->var.yoffset = var->yoffset;
924 if (var->vmode & FB_VMODE_YWRAP)
925 info->var.vmode |= FB_VMODE_YWRAP;
926 else
927 info->var.vmode &= ~FB_VMODE_YWRAP;
928 return 0;
929 }
930 EXPORT_SYMBOL(fb_pan_display);
931
932 static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
933 u32 activate)
934 {
935 struct fb_blit_caps caps, fbcaps;
936 int err = 0;
937
938 memset(&caps, 0, sizeof(caps));
939 memset(&fbcaps, 0, sizeof(fbcaps));
940 caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
941 fbcon_get_requirement(info, &caps);
942 info->fbops->fb_get_caps(info, &fbcaps, var);
943
944 if (((fbcaps.x ^ caps.x) & caps.x) ||
945 ((fbcaps.y ^ caps.y) & caps.y) ||
946 (fbcaps.len < caps.len))
947 err = -EINVAL;
948
949 return err;
950 }
951
952 int
953 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
954 {
955 int flags = info->flags;
956 int ret = 0;
957 u32 activate;
958 struct fb_var_screeninfo old_var;
959 struct fb_videomode mode;
960 struct fb_event event;
961
962 if (var->activate & FB_ACTIVATE_INV_MODE) {
963 struct fb_videomode mode1, mode2;
964
965 fb_var_to_videomode(&mode1, var);
966 fb_var_to_videomode(&mode2, &info->var);
967
968 ret = fb_mode_is_equal(&mode1, &mode2);
969
970 if (!ret)
971 fbcon_mode_deleted(info, &mode1);
972
973 if (!ret)
974 fb_delete_videomode(&mode1, &info->modelist);
975
976
977 return ret ? -EINVAL : 0;
978 }
979
980 if (!(var->activate & FB_ACTIVATE_FORCE) &&
981 !memcmp(&info->var, var, sizeof(struct fb_var_screeninfo)))
982 return 0;
983
984 activate = var->activate;
985
986
987
988
989 if ((info->fix.capabilities & FB_CAP_FOURCC) &&
990 var->grayscale > 1) {
991 if (var->red.offset || var->green.offset ||
992 var->blue.offset || var->transp.offset ||
993 var->red.length || var->green.length ||
994 var->blue.length || var->transp.length ||
995 var->red.msb_right || var->green.msb_right ||
996 var->blue.msb_right || var->transp.msb_right)
997 return -EINVAL;
998 }
999
1000 if (!info->fbops->fb_check_var) {
1001 *var = info->var;
1002 return 0;
1003 }
1004
1005 ret = info->fbops->fb_check_var(var, info);
1006
1007 if (ret)
1008 return ret;
1009
1010 if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
1011 return 0;
1012
1013 if (info->fbops->fb_get_caps) {
1014 ret = fb_check_caps(info, var, activate);
1015
1016 if (ret)
1017 return ret;
1018 }
1019
1020 old_var = info->var;
1021 info->var = *var;
1022
1023 if (info->fbops->fb_set_par) {
1024 ret = info->fbops->fb_set_par(info);
1025
1026 if (ret) {
1027 info->var = old_var;
1028 printk(KERN_WARNING "detected "
1029 "fb_set_par error, "
1030 "error code: %d\n", ret);
1031 return ret;
1032 }
1033 }
1034
1035 fb_pan_display(info, &info->var);
1036 fb_set_cmap(&info->cmap, info);
1037 fb_var_to_videomode(&mode, &info->var);
1038
1039 if (info->modelist.prev && info->modelist.next &&
1040 !list_empty(&info->modelist))
1041 ret = fb_add_videomode(&mode, &info->modelist);
1042
1043 if (ret)
1044 return ret;
1045
1046 event.info = info;
1047 event.data = &mode;
1048 fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event);
1049
1050 if (flags & FBINFO_MISC_USEREVENT)
1051 fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL);
1052
1053 return 0;
1054 }
1055 EXPORT_SYMBOL(fb_set_var);
1056
1057 int
1058 fb_blank(struct fb_info *info, int blank)
1059 {
1060 struct fb_event event;
1061 int ret = -EINVAL;
1062
1063 if (blank > FB_BLANK_POWERDOWN)
1064 blank = FB_BLANK_POWERDOWN;
1065
1066 event.info = info;
1067 event.data = ␣
1068
1069 if (info->fbops->fb_blank)
1070 ret = info->fbops->fb_blank(blank, info);
1071
1072 if (!ret)
1073 fb_notifier_call_chain(FB_EVENT_BLANK, &event);
1074
1075 return ret;
1076 }
1077 EXPORT_SYMBOL(fb_blank);
1078
1079 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1080 unsigned long arg)
1081 {
1082 struct fb_ops *fb;
1083 struct fb_var_screeninfo var;
1084 struct fb_fix_screeninfo fix;
1085 struct fb_cmap cmap_from;
1086 struct fb_cmap_user cmap;
1087 void __user *argp = (void __user *)arg;
1088 long ret = 0;
1089
1090 switch (cmd) {
1091 case FBIOGET_VSCREENINFO:
1092 lock_fb_info(info);
1093 var = info->var;
1094 unlock_fb_info(info);
1095
1096 ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
1097 break;
1098 case FBIOPUT_VSCREENINFO:
1099 if (copy_from_user(&var, argp, sizeof(var)))
1100 return -EFAULT;
1101 console_lock();
1102 lock_fb_info(info);
1103 info->flags |= FBINFO_MISC_USEREVENT;
1104 ret = fb_set_var(info, &var);
1105 info->flags &= ~FBINFO_MISC_USEREVENT;
1106 unlock_fb_info(info);
1107 console_unlock();
1108 if (!ret && copy_to_user(argp, &var, sizeof(var)))
1109 ret = -EFAULT;
1110 break;
1111 case FBIOGET_FSCREENINFO:
1112 lock_fb_info(info);
1113 memcpy(&fix, &info->fix, sizeof(fix));
1114 if (info->flags & FBINFO_HIDE_SMEM_START)
1115 fix.smem_start = 0;
1116 unlock_fb_info(info);
1117
1118 ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
1119 break;
1120 case FBIOPUTCMAP:
1121 if (copy_from_user(&cmap, argp, sizeof(cmap)))
1122 return -EFAULT;
1123 ret = fb_set_user_cmap(&cmap, info);
1124 break;
1125 case FBIOGETCMAP:
1126 if (copy_from_user(&cmap, argp, sizeof(cmap)))
1127 return -EFAULT;
1128 lock_fb_info(info);
1129 cmap_from = info->cmap;
1130 unlock_fb_info(info);
1131 ret = fb_cmap_to_user(&cmap_from, &cmap);
1132 break;
1133 case FBIOPAN_DISPLAY:
1134 if (copy_from_user(&var, argp, sizeof(var)))
1135 return -EFAULT;
1136 console_lock();
1137 lock_fb_info(info);
1138 ret = fb_pan_display(info, &var);
1139 unlock_fb_info(info);
1140 console_unlock();
1141 if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
1142 return -EFAULT;
1143 break;
1144 case FBIO_CURSOR:
1145 ret = -EINVAL;
1146 break;
1147 case FBIOGET_CON2FBMAP:
1148 ret = fbcon_get_con2fb_map_ioctl(argp);
1149 break;
1150 case FBIOPUT_CON2FBMAP:
1151 ret = fbcon_set_con2fb_map_ioctl(argp);
1152 break;
1153 case FBIOBLANK:
1154 console_lock();
1155 lock_fb_info(info);
1156 ret = fb_blank(info, arg);
1157
1158 fbcon_fb_blanked(info, arg);
1159 unlock_fb_info(info);
1160 console_unlock();
1161 break;
1162 default:
1163 lock_fb_info(info);
1164 fb = info->fbops;
1165 if (fb->fb_ioctl)
1166 ret = fb->fb_ioctl(info, cmd, arg);
1167 else
1168 ret = -ENOTTY;
1169 unlock_fb_info(info);
1170 }
1171 return ret;
1172 }
1173
1174 static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1175 {
1176 struct fb_info *info = file_fb_info(file);
1177
1178 if (!info)
1179 return -ENODEV;
1180 return do_fb_ioctl(info, cmd, arg);
1181 }
1182
1183 #ifdef CONFIG_COMPAT
1184 struct fb_fix_screeninfo32 {
1185 char id[16];
1186 compat_caddr_t smem_start;
1187 u32 smem_len;
1188 u32 type;
1189 u32 type_aux;
1190 u32 visual;
1191 u16 xpanstep;
1192 u16 ypanstep;
1193 u16 ywrapstep;
1194 u32 line_length;
1195 compat_caddr_t mmio_start;
1196 u32 mmio_len;
1197 u32 accel;
1198 u16 reserved[3];
1199 };
1200
1201 struct fb_cmap32 {
1202 u32 start;
1203 u32 len;
1204 compat_caddr_t red;
1205 compat_caddr_t green;
1206 compat_caddr_t blue;
1207 compat_caddr_t transp;
1208 };
1209
1210 static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
1211 unsigned long arg)
1212 {
1213 struct fb_cmap_user __user *cmap;
1214 struct fb_cmap32 __user *cmap32;
1215 __u32 data;
1216 int err;
1217
1218 cmap = compat_alloc_user_space(sizeof(*cmap));
1219 cmap32 = compat_ptr(arg);
1220
1221 if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
1222 return -EFAULT;
1223
1224 if (get_user(data, &cmap32->red) ||
1225 put_user(compat_ptr(data), &cmap->red) ||
1226 get_user(data, &cmap32->green) ||
1227 put_user(compat_ptr(data), &cmap->green) ||
1228 get_user(data, &cmap32->blue) ||
1229 put_user(compat_ptr(data), &cmap->blue) ||
1230 get_user(data, &cmap32->transp) ||
1231 put_user(compat_ptr(data), &cmap->transp))
1232 return -EFAULT;
1233
1234 err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
1235
1236 if (!err) {
1237 if (copy_in_user(&cmap32->start,
1238 &cmap->start,
1239 2 * sizeof(__u32)))
1240 err = -EFAULT;
1241 }
1242 return err;
1243 }
1244
1245 static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
1246 struct fb_fix_screeninfo32 __user *fix32)
1247 {
1248 __u32 data;
1249 int err;
1250
1251 err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
1252
1253 data = (__u32) (unsigned long) fix->smem_start;
1254 err |= put_user(data, &fix32->smem_start);
1255
1256 err |= put_user(fix->smem_len, &fix32->smem_len);
1257 err |= put_user(fix->type, &fix32->type);
1258 err |= put_user(fix->type_aux, &fix32->type_aux);
1259 err |= put_user(fix->visual, &fix32->visual);
1260 err |= put_user(fix->xpanstep, &fix32->xpanstep);
1261 err |= put_user(fix->ypanstep, &fix32->ypanstep);
1262 err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
1263 err |= put_user(fix->line_length, &fix32->line_length);
1264
1265 data = (__u32) (unsigned long) fix->mmio_start;
1266 err |= put_user(data, &fix32->mmio_start);
1267
1268 err |= put_user(fix->mmio_len, &fix32->mmio_len);
1269 err |= put_user(fix->accel, &fix32->accel);
1270 err |= copy_to_user(fix32->reserved, fix->reserved,
1271 sizeof(fix->reserved));
1272
1273 if (err)
1274 return -EFAULT;
1275 return 0;
1276 }
1277
1278 static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
1279 unsigned long arg)
1280 {
1281 struct fb_fix_screeninfo fix;
1282
1283 lock_fb_info(info);
1284 fix = info->fix;
1285 if (info->flags & FBINFO_HIDE_SMEM_START)
1286 fix.smem_start = 0;
1287 unlock_fb_info(info);
1288 return do_fscreeninfo_to_user(&fix, compat_ptr(arg));
1289 }
1290
1291 static long fb_compat_ioctl(struct file *file, unsigned int cmd,
1292 unsigned long arg)
1293 {
1294 struct fb_info *info = file_fb_info(file);
1295 struct fb_ops *fb;
1296 long ret = -ENOIOCTLCMD;
1297
1298 if (!info)
1299 return -ENODEV;
1300 fb = info->fbops;
1301 switch(cmd) {
1302 case FBIOGET_VSCREENINFO:
1303 case FBIOPUT_VSCREENINFO:
1304 case FBIOPAN_DISPLAY:
1305 case FBIOGET_CON2FBMAP:
1306 case FBIOPUT_CON2FBMAP:
1307 arg = (unsigned long) compat_ptr(arg);
1308
1309 case FBIOBLANK:
1310 ret = do_fb_ioctl(info, cmd, arg);
1311 break;
1312
1313 case FBIOGET_FSCREENINFO:
1314 ret = fb_get_fscreeninfo(info, cmd, arg);
1315 break;
1316
1317 case FBIOGETCMAP:
1318 case FBIOPUTCMAP:
1319 ret = fb_getput_cmap(info, cmd, arg);
1320 break;
1321
1322 default:
1323 if (fb->fb_compat_ioctl)
1324 ret = fb->fb_compat_ioctl(info, cmd, arg);
1325 break;
1326 }
1327 return ret;
1328 }
1329 #endif
1330
1331 static int
1332 fb_mmap(struct file *file, struct vm_area_struct * vma)
1333 {
1334 struct fb_info *info = file_fb_info(file);
1335 struct fb_ops *fb;
1336 unsigned long mmio_pgoff;
1337 unsigned long start;
1338 u32 len;
1339
1340 if (!info)
1341 return -ENODEV;
1342 fb = info->fbops;
1343 mutex_lock(&info->mm_lock);
1344 if (fb->fb_mmap) {
1345 int res;
1346
1347
1348
1349
1350
1351 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
1352 res = fb->fb_mmap(info, vma);
1353 mutex_unlock(&info->mm_lock);
1354 return res;
1355 }
1356
1357
1358
1359
1360
1361 start = info->fix.smem_start;
1362 len = info->fix.smem_len;
1363 mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
1364 if (vma->vm_pgoff >= mmio_pgoff) {
1365 if (info->var.accel_flags) {
1366 mutex_unlock(&info->mm_lock);
1367 return -EINVAL;
1368 }
1369
1370 vma->vm_pgoff -= mmio_pgoff;
1371 start = info->fix.mmio_start;
1372 len = info->fix.mmio_len;
1373 }
1374 mutex_unlock(&info->mm_lock);
1375
1376 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
1377
1378
1379
1380
1381 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
1382 fb_pgprotect(file, vma, start);
1383
1384 return vm_iomap_memory(vma, start, len);
1385 }
1386
1387 static int
1388 fb_open(struct inode *inode, struct file *file)
1389 __acquires(&info->lock)
1390 __releases(&info->lock)
1391 {
1392 int fbidx = iminor(inode);
1393 struct fb_info *info;
1394 int res = 0;
1395
1396 info = get_fb_info(fbidx);
1397 if (!info) {
1398 request_module("fb%d", fbidx);
1399 info = get_fb_info(fbidx);
1400 if (!info)
1401 return -ENODEV;
1402 }
1403 if (IS_ERR(info))
1404 return PTR_ERR(info);
1405
1406 lock_fb_info(info);
1407 if (!try_module_get(info->fbops->owner)) {
1408 res = -ENODEV;
1409 goto out;
1410 }
1411 file->private_data = info;
1412 if (info->fbops->fb_open) {
1413 res = info->fbops->fb_open(info,1);
1414 if (res)
1415 module_put(info->fbops->owner);
1416 }
1417 #ifdef CONFIG_FB_DEFERRED_IO
1418 if (info->fbdefio)
1419 fb_deferred_io_open(info, inode, file);
1420 #endif
1421 out:
1422 unlock_fb_info(info);
1423 if (res)
1424 put_fb_info(info);
1425 return res;
1426 }
1427
1428 static int
1429 fb_release(struct inode *inode, struct file *file)
1430 __acquires(&info->lock)
1431 __releases(&info->lock)
1432 {
1433 struct fb_info * const info = file->private_data;
1434
1435 lock_fb_info(info);
1436 if (info->fbops->fb_release)
1437 info->fbops->fb_release(info,1);
1438 module_put(info->fbops->owner);
1439 unlock_fb_info(info);
1440 put_fb_info(info);
1441 return 0;
1442 }
1443
1444 #if defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && !defined(CONFIG_MMU)
1445 unsigned long get_fb_unmapped_area(struct file *filp,
1446 unsigned long addr, unsigned long len,
1447 unsigned long pgoff, unsigned long flags)
1448 {
1449 struct fb_info * const info = filp->private_data;
1450 unsigned long fb_size = PAGE_ALIGN(info->fix.smem_len);
1451
1452 if (pgoff > fb_size || len > fb_size - pgoff)
1453 return -EINVAL;
1454
1455 return (unsigned long)info->screen_base + pgoff;
1456 }
1457 #endif
1458
1459 static const struct file_operations fb_fops = {
1460 .owner = THIS_MODULE,
1461 .read = fb_read,
1462 .write = fb_write,
1463 .unlocked_ioctl = fb_ioctl,
1464 #ifdef CONFIG_COMPAT
1465 .compat_ioctl = fb_compat_ioctl,
1466 #endif
1467 .mmap = fb_mmap,
1468 .open = fb_open,
1469 .release = fb_release,
1470 #if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \
1471 (defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \
1472 !defined(CONFIG_MMU))
1473 .get_unmapped_area = get_fb_unmapped_area,
1474 #endif
1475 #ifdef CONFIG_FB_DEFERRED_IO
1476 .fsync = fb_deferred_io_fsync,
1477 #endif
1478 .llseek = default_llseek,
1479 };
1480
1481 struct class *fb_class;
1482 EXPORT_SYMBOL(fb_class);
1483
1484 static int fb_check_foreignness(struct fb_info *fi)
1485 {
1486 const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
1487
1488 fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
1489
1490 #ifdef __BIG_ENDIAN
1491 fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
1492 #else
1493 fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
1494 #endif
1495
1496 if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
1497 pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
1498 "support this framebuffer\n", fi->fix.id);
1499 return -ENOSYS;
1500 } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
1501 pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
1502 "support this framebuffer\n", fi->fix.id);
1503 return -ENOSYS;
1504 }
1505
1506 return 0;
1507 }
1508
1509 static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
1510 {
1511
1512 if (gen->base == hw->base)
1513 return true;
1514
1515 if (gen->base > hw->base && gen->base < hw->base + hw->size)
1516 return true;
1517 return false;
1518 }
1519
1520 static bool fb_do_apertures_overlap(struct apertures_struct *gena,
1521 struct apertures_struct *hwa)
1522 {
1523 int i, j;
1524 if (!hwa || !gena)
1525 return false;
1526
1527 for (i = 0; i < hwa->count; ++i) {
1528 struct aperture *h = &hwa->ranges[i];
1529 for (j = 0; j < gena->count; ++j) {
1530 struct aperture *g = &gena->ranges[j];
1531 printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
1532 (unsigned long long)g->base,
1533 (unsigned long long)g->size,
1534 (unsigned long long)h->base,
1535 (unsigned long long)h->size);
1536 if (apertures_overlap(g, h))
1537 return true;
1538 }
1539 }
1540
1541 return false;
1542 }
1543
1544 static void do_unregister_framebuffer(struct fb_info *fb_info);
1545
1546 #define VGA_FB_PHYS 0xA0000
1547 static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
1548 const char *name, bool primary)
1549 {
1550 int i;
1551
1552
1553 for_each_registered_fb(i) {
1554 struct apertures_struct *gen_aper;
1555
1556 if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
1557 continue;
1558
1559 gen_aper = registered_fb[i]->apertures;
1560 if (fb_do_apertures_overlap(gen_aper, a) ||
1561 (primary && gen_aper && gen_aper->count &&
1562 gen_aper->ranges[0].base == VGA_FB_PHYS)) {
1563
1564 printk(KERN_INFO "fb%d: switching to %s from %s\n",
1565 i, name, registered_fb[i]->fix.id);
1566 do_unregister_framebuffer(registered_fb[i]);
1567 }
1568 }
1569 }
1570
1571 static bool lockless_register_fb;
1572 module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
1573 MODULE_PARM_DESC(lockless_register_fb,
1574 "Lockless framebuffer registration for debugging [default=off]");
1575
1576 static int do_register_framebuffer(struct fb_info *fb_info)
1577 {
1578 int i, ret;
1579 struct fb_videomode mode;
1580
1581 if (fb_check_foreignness(fb_info))
1582 return -ENOSYS;
1583
1584 do_remove_conflicting_framebuffers(fb_info->apertures,
1585 fb_info->fix.id,
1586 fb_is_primary_device(fb_info));
1587
1588 if (num_registered_fb == FB_MAX)
1589 return -ENXIO;
1590
1591 num_registered_fb++;
1592 for (i = 0 ; i < FB_MAX; i++)
1593 if (!registered_fb[i])
1594 break;
1595 fb_info->node = i;
1596 atomic_set(&fb_info->count, 1);
1597 mutex_init(&fb_info->lock);
1598 mutex_init(&fb_info->mm_lock);
1599
1600 fb_info->dev = device_create(fb_class, fb_info->device,
1601 MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
1602 if (IS_ERR(fb_info->dev)) {
1603
1604 printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
1605 fb_info->dev = NULL;
1606 } else
1607 fb_init_device(fb_info);
1608
1609 if (fb_info->pixmap.addr == NULL) {
1610 fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
1611 if (fb_info->pixmap.addr) {
1612 fb_info->pixmap.size = FBPIXMAPSIZE;
1613 fb_info->pixmap.buf_align = 1;
1614 fb_info->pixmap.scan_align = 1;
1615 fb_info->pixmap.access_align = 32;
1616 fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
1617 }
1618 }
1619 fb_info->pixmap.offset = 0;
1620
1621 if (!fb_info->pixmap.blit_x)
1622 fb_info->pixmap.blit_x = ~(u32)0;
1623
1624 if (!fb_info->pixmap.blit_y)
1625 fb_info->pixmap.blit_y = ~(u32)0;
1626
1627 if (!fb_info->modelist.prev || !fb_info->modelist.next)
1628 INIT_LIST_HEAD(&fb_info->modelist);
1629
1630 if (fb_info->skip_vt_switch)
1631 pm_vt_switch_required(fb_info->dev, false);
1632 else
1633 pm_vt_switch_required(fb_info->dev, true);
1634
1635 fb_var_to_videomode(&mode, &fb_info->var);
1636 fb_add_videomode(&mode, &fb_info->modelist);
1637 registered_fb[i] = fb_info;
1638
1639 #ifdef CONFIG_GUMSTIX_AM200EPD
1640 {
1641 struct fb_event event;
1642 event.info = fb_info;
1643 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1644 }
1645 #endif
1646
1647 if (!lockless_register_fb)
1648 console_lock();
1649 else
1650 atomic_inc(&ignore_console_lock_warning);
1651 lock_fb_info(fb_info);
1652 ret = fbcon_fb_registered(fb_info);
1653 unlock_fb_info(fb_info);
1654
1655 if (!lockless_register_fb)
1656 console_unlock();
1657 else
1658 atomic_dec(&ignore_console_lock_warning);
1659 return ret;
1660 }
1661
1662 static void unbind_console(struct fb_info *fb_info)
1663 {
1664 int i = fb_info->node;
1665
1666 if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
1667 return;
1668
1669 console_lock();
1670 lock_fb_info(fb_info);
1671 fbcon_fb_unbind(fb_info);
1672 unlock_fb_info(fb_info);
1673 console_unlock();
1674 }
1675
1676 void unlink_framebuffer(struct fb_info *fb_info)
1677 {
1678 int i;
1679
1680 i = fb_info->node;
1681 if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
1682 return;
1683
1684 if (!fb_info->dev)
1685 return;
1686
1687 device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1688
1689 pm_vt_switch_unregister(fb_info->dev);
1690
1691 unbind_console(fb_info);
1692
1693 fb_info->dev = NULL;
1694 }
1695 EXPORT_SYMBOL(unlink_framebuffer);
1696
1697 static void do_unregister_framebuffer(struct fb_info *fb_info)
1698 {
1699 unlink_framebuffer(fb_info);
1700 if (fb_info->pixmap.addr &&
1701 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
1702 kfree(fb_info->pixmap.addr);
1703 fb_destroy_modelist(&fb_info->modelist);
1704 registered_fb[fb_info->node] = NULL;
1705 num_registered_fb--;
1706 fb_cleanup_device(fb_info);
1707 #ifdef CONFIG_GUMSTIX_AM200EPD
1708 {
1709 struct fb_event event;
1710 event.info = fb_info;
1711 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1712 }
1713 #endif
1714 console_lock();
1715 fbcon_fb_unregistered(fb_info);
1716 console_unlock();
1717
1718
1719 put_fb_info(fb_info);
1720 }
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732 int remove_conflicting_framebuffers(struct apertures_struct *a,
1733 const char *name, bool primary)
1734 {
1735 bool do_free = false;
1736
1737 if (!a) {
1738 a = alloc_apertures(1);
1739 if (!a)
1740 return -ENOMEM;
1741
1742 a->ranges[0].base = 0;
1743 a->ranges[0].size = ~0;
1744 do_free = true;
1745 }
1746
1747 mutex_lock(®istration_lock);
1748 do_remove_conflicting_framebuffers(a, name, primary);
1749 mutex_unlock(®istration_lock);
1750
1751 if (do_free)
1752 kfree(a);
1753
1754 return 0;
1755 }
1756 EXPORT_SYMBOL(remove_conflicting_framebuffers);
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770 int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id, const char *name)
1771 {
1772 struct apertures_struct *ap;
1773 bool primary = false;
1774 int err, idx, bar;
1775 bool res_id_found = false;
1776
1777 for (idx = 0, bar = 0; bar < PCI_ROM_RESOURCE; bar++) {
1778 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
1779 continue;
1780 idx++;
1781 }
1782
1783 ap = alloc_apertures(idx);
1784 if (!ap)
1785 return -ENOMEM;
1786
1787 for (idx = 0, bar = 0; bar < PCI_ROM_RESOURCE; bar++) {
1788 if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
1789 continue;
1790 ap->ranges[idx].base = pci_resource_start(pdev, bar);
1791 ap->ranges[idx].size = pci_resource_len(pdev, bar);
1792 pci_info(pdev, "%s: bar %d: 0x%lx -> 0x%lx\n", __func__, bar,
1793 (unsigned long)pci_resource_start(pdev, bar),
1794 (unsigned long)pci_resource_end(pdev, bar));
1795 idx++;
1796 if (res_id == bar)
1797 res_id_found = true;
1798 }
1799 if (!res_id_found)
1800 pci_warn(pdev, "%s: passed res_id (%d) is not a memory bar\n",
1801 __func__, res_id);
1802
1803 #ifdef CONFIG_X86
1804 primary = pdev->resource[PCI_ROM_RESOURCE].flags &
1805 IORESOURCE_ROM_SHADOW;
1806 #endif
1807 err = remove_conflicting_framebuffers(ap, name, primary);
1808 kfree(ap);
1809 return err;
1810 }
1811 EXPORT_SYMBOL(remove_conflicting_pci_framebuffers);
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822 int
1823 register_framebuffer(struct fb_info *fb_info)
1824 {
1825 int ret;
1826
1827 mutex_lock(®istration_lock);
1828 ret = do_register_framebuffer(fb_info);
1829 mutex_unlock(®istration_lock);
1830
1831 return ret;
1832 }
1833 EXPORT_SYMBOL(register_framebuffer);
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851 void
1852 unregister_framebuffer(struct fb_info *fb_info)
1853 {
1854 mutex_lock(®istration_lock);
1855 do_unregister_framebuffer(fb_info);
1856 mutex_unlock(®istration_lock);
1857 }
1858 EXPORT_SYMBOL(unregister_framebuffer);
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869 void fb_set_suspend(struct fb_info *info, int state)
1870 {
1871 WARN_CONSOLE_UNLOCKED();
1872
1873 if (state) {
1874 fbcon_suspended(info);
1875 info->state = FBINFO_STATE_SUSPENDED;
1876 } else {
1877 info->state = FBINFO_STATE_RUNNING;
1878 fbcon_resumed(info);
1879 }
1880 }
1881 EXPORT_SYMBOL(fb_set_suspend);
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892 static int __init
1893 fbmem_init(void)
1894 {
1895 int ret;
1896
1897 if (!proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops))
1898 return -ENOMEM;
1899
1900 ret = register_chrdev(FB_MAJOR, "fb", &fb_fops);
1901 if (ret) {
1902 printk("unable to get major %d for fb devs\n", FB_MAJOR);
1903 goto err_chrdev;
1904 }
1905
1906 fb_class = class_create(THIS_MODULE, "graphics");
1907 if (IS_ERR(fb_class)) {
1908 ret = PTR_ERR(fb_class);
1909 pr_warn("Unable to create fb class; errno = %d\n", ret);
1910 fb_class = NULL;
1911 goto err_class;
1912 }
1913
1914 fb_console_init();
1915
1916 return 0;
1917
1918 err_class:
1919 unregister_chrdev(FB_MAJOR, "fb");
1920 err_chrdev:
1921 remove_proc_entry("fb", NULL);
1922 return ret;
1923 }
1924
1925 #ifdef MODULE
1926 module_init(fbmem_init);
1927 static void __exit
1928 fbmem_exit(void)
1929 {
1930 fb_console_exit();
1931
1932 remove_proc_entry("fb", NULL);
1933 class_destroy(fb_class);
1934 unregister_chrdev(FB_MAJOR, "fb");
1935 }
1936
1937 module_exit(fbmem_exit);
1938 MODULE_LICENSE("GPL");
1939 MODULE_DESCRIPTION("Framebuffer base");
1940 #else
1941 subsys_initcall(fbmem_init);
1942 #endif
1943
1944 int fb_new_modelist(struct fb_info *info)
1945 {
1946 struct fb_var_screeninfo var = info->var;
1947 struct list_head *pos, *n;
1948 struct fb_modelist *modelist;
1949 struct fb_videomode *m, mode;
1950 int err;
1951
1952 list_for_each_safe(pos, n, &info->modelist) {
1953 modelist = list_entry(pos, struct fb_modelist, list);
1954 m = &modelist->mode;
1955 fb_videomode_to_var(&var, m);
1956 var.activate = FB_ACTIVATE_TEST;
1957 err = fb_set_var(info, &var);
1958 fb_var_to_videomode(&mode, &var);
1959 if (err || !fb_mode_is_equal(m, &mode)) {
1960 list_del(pos);
1961 kfree(pos);
1962 }
1963 }
1964
1965 if (list_empty(&info->modelist))
1966 return 1;
1967
1968 fbcon_new_modelist(info);
1969
1970 return 0;
1971 }
1972
1973 MODULE_LICENSE("GPL");