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