LCOV - code coverage report
Current view: top level - drivers/video/fbdev/core - fbmem.c (source / functions) Hit Total Coverage
Test: Real Lines: 300 717 41.8 %
Date: 2020-10-17 15:46:16 Functions: 3 44 6.8 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

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

Generated by: LCOV version 1.14