LCOV - code coverage report
Current view: top level - lkbce/drivers/video - fbmem.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 607 780 77.8 %
Date: 2017-01-25 Functions: 25 36 69.4 %

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

Generated by: LCOV version 1.10