git.y1.nz

fbui

Framebuffer-based graphical environment
download: https://git.y1.nz/archives/fbui.tar.gz
README | Files | Log | Refs

drivers/video/fbmem.c

      1 /*
      2  *  linux/drivers/video/fbmem.c
      3  *
      4  *  Copyright (C) 1994 Martin Schaller
      5  *
      6  *	2001 - Documented with DocBook
      7  *	- Brad Douglas <brad@neruo.com>
      8  *      2004 - Updated for fbui
      9  *      - Zack T Smith <fbui@comcast.net>
     10  *
     11  * This file is subject to the terms and conditions of the GNU General Public
     12  * License.  See the file COPYING in the main directory of this archive
     13  * for more details.
     14  */
     15 
     16 #include <linux/config.h>
     17 #include <linux/module.h>
     18 
     19 #include <linux/types.h>
     20 #include <linux/errno.h>
     21 #include <linux/sched.h>
     22 #include <linux/smp_lock.h>
     23 #include <linux/kernel.h>
     24 #include <linux/major.h>
     25 #include <linux/slab.h>
     26 #include <linux/mm.h>
     27 #include <linux/mman.h>
     28 #include <linux/tty.h>
     29 #include <linux/init.h>
     30 #include <linux/linux_logo.h>
     31 #include <linux/proc_fs.h>
     32 #include <linux/console.h>
     33 #ifdef CONFIG_KMOD
     34 #include <linux/kmod.h>
     35 #endif
     36 #include <linux/devfs_fs_kernel.h>
     37 #include <linux/err.h>
     38 #include <linux/kernel.h>
     39 #include <linux/device.h>
     40 
     41 #if defined(__mc68000__) || defined(CONFIG_APUS)
     42 #include <asm/setup.h>
     43 #endif
     44 
     45 #include <asm/io.h>
     46 #include <asm/uaccess.h>
     47 #include <asm/page.h>
     48 #include <asm/pgtable.h>
     49 
     50 #include <linux/fb.h>
     51 
     52     /*
     53      *  Frame buffer device initialization and setup routines
     54      */
     55 
     56 #define FBPIXMAPSIZE	16384
     57 
     58 static struct notifier_block *fb_notifier_list;
     59 struct fb_info *registered_fb[FB_MAX];
     60 int num_registered_fb;
     61 
     62 /*
     63  * Helpers
     64  */
     65 
     66 int fb_get_color_depth(struct fb_info *info)
     67 {
     68 	struct fb_var_screeninfo *var = &info->var;
     69 
     70 	if (var->green.length == var->blue.length &&
     71 	    var->green.length == var->red.length &&
     72 	    !var->green.offset && !var->blue.offset &&
     73 	    !var->red.offset)
     74 		return var->green.length;
     75 	else
     76 		return (var->green.length + var->red.length +
     77 			var->blue.length);
     78 }
     79 EXPORT_SYMBOL(fb_get_color_depth);
     80 
     81 /*
     82  * Drawing helpers.
     83  */
     84 void fb_iomove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
     85 			   u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
     86 			   u32 height)
     87 {
     88 	int i;
     89 
     90 	for (i = height; i--; ) {
     91 		buf->outbuf(info, dst, src, s_pitch);
     92 		src += s_pitch;
     93 		dst += d_pitch;
     94 	}
     95 }
     96 
     97 void fb_sysmove_buf_aligned(struct fb_info *info, struct fb_pixmap *buf,
     98 			    u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
     99 			    u32 height)
    100 {
    101 	int i, j;
    102 
    103 	for (i = height; i--; ) {
    104 		for (j = 0; j < s_pitch; j++)
    105 			dst[j] = src[j];
    106 		src += s_pitch;
    107 		dst += d_pitch;
    108 	}
    109 }
    110 
    111 void fb_iomove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
    112 			     u8 *dst, u32 d_pitch, u8 *src, u32 idx,
    113 			     u32 height, u32 shift_high, u32 shift_low,
    114 			     u32 mod)
    115 {
    116 	u8 mask = (u8) (0xfff << shift_high), tmp;
    117 	int i, j;
    118 
    119 	for (i = height; i--; ) {
    120 		for (j = 0; j < idx; j++) {
    121 			tmp = buf->inbuf(info, dst+j);
    122 			tmp &= mask;
    123 			tmp |= *src >> shift_low;
    124 			buf->outbuf(info, dst+j, &tmp, 1);
    125 			tmp = *src << shift_high;
    126 			buf->outbuf(info, dst+j+1, &tmp, 1);
    127 			src++;
    128 		}
    129 		tmp = buf->inbuf(info, dst+idx);
    130 		tmp &= mask;
    131 		tmp |= *src >> shift_low;
    132 		buf->outbuf(info, dst+idx, &tmp, 1);
    133 		if (shift_high < mod) {
    134 			tmp = *src << shift_high;
    135 			buf->outbuf(info, dst+idx+1, &tmp, 1);
    136 		}	
    137 		src++;
    138 		dst += d_pitch;
    139 	}
    140 }
    141 
    142 void fb_sysmove_buf_unaligned(struct fb_info *info, struct fb_pixmap *buf,
    143 			      u8 *dst, u32 d_pitch, u8 *src, u32 idx,
    144 			      u32 height, u32 shift_high, u32 shift_low,
    145 			      u32 mod)
    146 {
    147 	u8 mask = (u8) (0xfff << shift_high), tmp;
    148 	int i, j;
    149 
    150 	for (i = height; i--; ) {
    151 		for (j = 0; j < idx; j++) {
    152 			tmp = dst[j];
    153 			tmp &= mask;
    154 			tmp |= *src >> shift_low;
    155 			dst[j] = tmp;
    156 			tmp = *src << shift_high;
    157 			dst[j+1] = tmp;
    158 			src++;
    159 		}
    160 		tmp = dst[idx];
    161 		tmp &= mask;
    162 		tmp |= *src >> shift_low;
    163 		dst[idx] = tmp;
    164 		if (shift_high < mod) {
    165 			tmp = *src << shift_high;
    166 			dst[idx+1] = tmp;
    167 		}
    168 		src++;
    169 		dst += d_pitch;
    170 	}
    171 }
    172 
    173 /*
    174  * we need to lock this section since fb_cursor
    175  * may use fb_imageblit()
    176  */
    177 char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
    178 {
    179 	u32 align = buf->buf_align - 1, offset;
    180 	char *addr = buf->addr;
    181 
    182 	/* If IO mapped, we need to sync before access, no sharing of
    183 	 * the pixmap is done
    184 	 */
    185 	if (buf->flags & FB_PIXMAP_IO) {
    186 		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
    187 			info->fbops->fb_sync(info);
    188 		return addr;
    189 	}
    190 
    191 	/* See if we fit in the remaining pixmap space */
    192 	offset = buf->offset + align;
    193 	offset &= ~align;
    194 	if (offset + size > buf->size) {
    195 		/* We do not fit. In order to be able to re-use the buffer,
    196 		 * we must ensure no asynchronous DMA'ing or whatever operation
    197 		 * is in progress, we sync for that.
    198 		 */
    199 		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
    200 			info->fbops->fb_sync(info);
    201 		offset = 0;
    202 	}
    203 	buf->offset = offset + size;
    204 	addr += offset;
    205 
    206 	return addr;
    207 }
    208 
    209 #ifdef CONFIG_LOGO
    210 #include <linux/linux_logo.h>
    211 
    212 static inline unsigned safe_shift(unsigned d, int n)
    213 {
    214 	return n < 0 ? d >> -n : d << n;
    215 }
    216 
    217 static void fb_set_logocmap(struct fb_info *info,
    218 				   const struct linux_logo *logo)
    219 {
    220 	struct fb_cmap palette_cmap;
    221 	u16 palette_green[16];
    222 	u16 palette_blue[16];
    223 	u16 palette_red[16];
    224 	int i, j, n;
    225 	const unsigned char *clut = logo->clut;
    226 
    227 	palette_cmap.start = 0;
    228 	palette_cmap.len = 16;
    229 	palette_cmap.red = palette_red;
    230 	palette_cmap.green = palette_green;
    231 	palette_cmap.blue = palette_blue;
    232 	palette_cmap.transp = NULL;
    233 
    234 	for (i = 0; i < logo->clutsize; i += n) {
    235 		n = logo->clutsize - i;
    236 		/* palette_cmap provides space for only 16 colors at once */
    237 		if (n > 16)
    238 			n = 16;
    239 		palette_cmap.start = 32 + i;
    240 		palette_cmap.len = n;
    241 		for (j = 0; j < n; ++j) {
    242 			palette_cmap.red[j] = clut[0] << 8 | clut[0];
    243 			palette_cmap.green[j] = clut[1] << 8 | clut[1];
    244 			palette_cmap.blue[j] = clut[2] << 8 | clut[2];
    245 			clut += 3;
    246 		}
    247 		fb_set_cmap(&palette_cmap, info);
    248 	}
    249 }
    250 
    251 static void  fb_set_logo_truepalette(struct fb_info *info,
    252 					    const struct linux_logo *logo,
    253 					    u32 *palette)
    254 {
    255 	unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
    256 	unsigned char redmask, greenmask, bluemask;
    257 	int redshift, greenshift, blueshift;
    258 	int i;
    259 	const unsigned char *clut = logo->clut;
    260 
    261 	/*
    262 	 * We have to create a temporary palette since console palette is only
    263 	 * 16 colors long.
    264 	 */
    265 	/* Bug: Doesn't obey msb_right ... (who needs that?) */
    266 	redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];
    267 	greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
    268 	bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];
    269 	redshift   = info->var.red.offset   - (8 - info->var.red.length);
    270 	greenshift = info->var.green.offset - (8 - info->var.green.length);
    271 	blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);
    272 
    273 	for ( i = 0; i < logo->clutsize; i++) {
    274 		palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
    275 				 safe_shift((clut[1] & greenmask), greenshift) |
    276 				 safe_shift((clut[2] & bluemask), blueshift));
    277 		clut += 3;
    278 	}
    279 }
    280 
    281 static void fb_set_logo_directpalette(struct fb_info *info,
    282 					     const struct linux_logo *logo,
    283 					     u32 *palette)
    284 {
    285 	int redshift, greenshift, blueshift;
    286 	int i;
    287 
    288 	redshift = info->var.red.offset;
    289 	greenshift = info->var.green.offset;
    290 	blueshift = info->var.blue.offset;
    291 
    292 	for (i = 32; i < logo->clutsize; i++)
    293 		palette[i] = i << redshift | i << greenshift | i << blueshift;
    294 }
    295 
    296 static void fb_set_logo(struct fb_info *info,
    297 			       const struct linux_logo *logo, u8 *dst,
    298 			       int depth)
    299 {
    300 	int i, j, k, fg = 1;
    301 	const u8 *src = logo->data;
    302 	u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
    303 
    304 	if (fb_get_color_depth(info) == 3)
    305 		fg = 7;
    306 
    307 	switch (depth) {
    308 	case 4:
    309 		for (i = 0; i < logo->height; i++)
    310 			for (j = 0; j < logo->width; src++) {
    311 				*dst++ = *src >> 4;
    312 				j++;
    313 				if (j < logo->width) {
    314 					*dst++ = *src & 0x0f;
    315 					j++;
    316 				}
    317 			}
    318 		break;
    319 	case 1:
    320 		for (i = 0; i < logo->height; i++) {
    321 			for (j = 0; j < logo->width; src++) {
    322 				d = *src ^ xor;
    323 				for (k = 7; k >= 0; k--) {
    324 					*dst++ = ((d >> k) & 1) ? fg : 0;
    325 					j++;
    326 				}
    327 			}
    328 		}
    329 		break;
    330 	}
    331 }
    332 
    333 /*
    334  * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors),
    335  * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on
    336  * the visual format and color depth of the framebuffer, the DAC, the
    337  * pseudo_palette, and the logo data will be adjusted accordingly.
    338  *
    339  * Case 1 - linux_logo_clut224:
    340  * Color exceeds the number of console colors (16), thus we set the hardware DAC
    341  * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set.
    342  *
    343  * For visuals that require color info from the pseudo_palette, we also construct
    344  * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
    345  * will be set.
    346  *
    347  * Case 2 - linux_logo_vga16:
    348  * The number of colors just matches the console colors, thus there is no need
    349  * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie,
    350  * each byte contains color information for two pixels (upper and lower nibble).
    351  * To be consistent with fb_imageblit() usage, we therefore separate the two
    352  * nibbles into separate bytes. The "depth" flag will be set to 4.
    353  *
    354  * Case 3 - linux_logo_mono:
    355  * This is similar with Case 2.  Each byte contains information for 8 pixels.
    356  * We isolate each bit and expand each into a byte. The "depth" flag will
    357  * be set to 1.
    358  */
    359 static struct logo_data {
    360 	int depth;
    361 	int needs_directpalette;
    362 	int needs_truepalette;
    363 	int needs_cmapreset;
    364 	const struct linux_logo *logo;
    365 } fb_logo;
    366 
    367 int fb_prepare_logo(struct fb_info *info)
    368 {
    369 	int depth = fb_get_color_depth(info);
    370 
    371 	memset(&fb_logo, 0, sizeof(struct logo_data));
    372 
    373 	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
    374 		depth = info->var.blue.length;
    375 		if (info->var.red.length < depth)
    376 			depth = info->var.red.length;
    377 		if (info->var.green.length < depth)
    378 			depth = info->var.green.length;
    379 	}
    380 
    381 	if (depth >= 8) {
    382 		switch (info->fix.visual) {
    383 		case FB_VISUAL_TRUECOLOR:
    384 			fb_logo.needs_truepalette = 1;
    385 			break;
    386 		case FB_VISUAL_DIRECTCOLOR:
    387 			fb_logo.needs_directpalette = 1;
    388 			fb_logo.needs_cmapreset = 1;
    389 			break;
    390 		case FB_VISUAL_PSEUDOCOLOR:
    391 			fb_logo.needs_cmapreset = 1;
    392 			break;
    393 		}
    394 	}
    395 
    396 	/* Return if no suitable logo was found */
    397 	fb_logo.logo = fb_find_logo(depth);
    398 	
    399 	if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
    400 		fb_logo.logo = NULL;
    401 		return 0;
    402 	}
    403 	/* What depth we asked for might be different from what we get */
    404 	if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
    405 		fb_logo.depth = 8;
    406 	else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
    407 		fb_logo.depth = 4;
    408 	else
    409 		fb_logo.depth = 1;		
    410 	return fb_logo.logo->height;
    411 }
    412 
    413 int fb_show_logo(struct fb_info *info)
    414 {
    415 	u32 *palette = NULL, *saved_pseudo_palette = NULL;
    416 	unsigned char *logo_new = NULL;
    417 	struct fb_image image;
    418 	int x;
    419 
    420 	/* Return if the frame buffer is not mapped or suspended */
    421 	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
    422 		return 0;
    423 
    424 	image.depth = 8;
    425 	image.data = fb_logo.logo->data;
    426 
    427 	if (fb_logo.needs_cmapreset)
    428 		fb_set_logocmap(info, fb_logo.logo);
    429 
    430 	if (fb_logo.needs_truepalette || 
    431 	    fb_logo.needs_directpalette) {
    432 		palette = kmalloc(256 * 4, GFP_KERNEL);
    433 		if (palette == NULL)
    434 			return 0;
    435 
    436 		if (fb_logo.needs_truepalette)
    437 			fb_set_logo_truepalette(info, fb_logo.logo, palette);
    438 		else
    439 			fb_set_logo_directpalette(info, fb_logo.logo, palette);
    440 
    441 		saved_pseudo_palette = info->pseudo_palette;
    442 		info->pseudo_palette = palette;
    443 	}
    444 
    445 	if (fb_logo.depth <= 4) {
    446 		logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, 
    447 				   GFP_KERNEL);
    448 		if (logo_new == NULL) {
    449 			if (palette)
    450 				kfree(palette);
    451 			if (saved_pseudo_palette)
    452 				info->pseudo_palette = saved_pseudo_palette;
    453 			return 0;
    454 		}
    455 		image.data = logo_new;
    456 		fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
    457 	}
    458 
    459 	image.width = fb_logo.logo->width;
    460 	image.height = fb_logo.logo->height;
    461 	image.dy = 0;
    462 
    463 	for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&
    464 	     x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
    465 		image.dx = x;
    466 		info->fbops->fb_imageblit(info, &image);
    467 	}
    468 	
    469 	if (palette != NULL)
    470 		kfree(palette);
    471 	if (saved_pseudo_palette != NULL)
    472 		info->pseudo_palette = saved_pseudo_palette;
    473 	if (logo_new != NULL)
    474 		kfree(logo_new);
    475 	return fb_logo.logo->height;
    476 }
    477 #else
    478 int fb_prepare_logo(struct fb_info *info) { return 0; }
    479 int fb_show_logo(struct fb_info *info) { return 0; }
    480 #endif /* CONFIG_LOGO */
    481 
    482 static int fbmem_read_proc(char *buf, char **start, off_t offset,
    483 			   int len, int *eof, void *private)
    484 {
    485 	struct fb_info **fi;
    486 	int clen;
    487 
    488 	clen = 0;
    489 	for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
    490 		if (*fi)
    491 			clen += sprintf(buf + clen, "%d %s\n",
    492 				        (*fi)->node,
    493 				        (*fi)->fix.id);
    494 	*start = buf + offset;
    495 	if (clen > offset)
    496 		clen -= offset;
    497 	else
    498 		clen = 0;
    499 	return clen < len ? clen : len;
    500 }
    501 
    502 static ssize_t
    503 fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
    504 {
    505 	unsigned long p = *ppos;
    506 	struct inode *inode = file->f_dentry->d_inode;
    507 	int fbidx = iminor(inode);
    508 	struct fb_info *info = registered_fb[fbidx];
    509 	u32 *buffer, *dst, *src;
    510 	int c, i, cnt = 0, err = 0;
    511 	unsigned long total_size;
    512 
    513 	if (!info || ! info->screen_base)
    514 		return -ENODEV;
    515 
    516 	if (info->state != FBINFO_STATE_RUNNING)
    517 		return -EPERM;
    518 
    519 	if (info->fbops->fb_read)
    520 		return info->fbops->fb_read(file, buf, count, ppos);
    521 	
    522 	total_size = info->screen_size;
    523 	if (total_size == 0)
    524 		total_size = info->fix.smem_len;
    525 
    526 	if (p >= total_size)
    527 	    return 0;
    528 	if (count >= total_size)
    529 	    count = total_size;
    530 	if (count + p > total_size)
    531 		count = total_size - p;
    532 
    533 	cnt = 0;
    534 	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
    535 			 GFP_KERNEL);
    536 	if (!buffer)
    537 		return -ENOMEM;
    538 
    539 	src = (u32 *) (info->screen_base + p);
    540 
    541 	if (info->fbops->fb_sync)
    542 		info->fbops->fb_sync(info);
    543 
    544 	while (count) {
    545 		c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
    546 		dst = buffer;
    547 		for (i = c >> 2; i--; )
    548 			*dst++ = fb_readl(src++);
    549 		if (c & 3) {
    550 			u8 *dst8 = (u8 *) dst;
    551 			u8 *src8 = (u8 *) src;
    552 
    553 			for (i = c & 3; i--;)
    554 				*dst8++ = fb_readb(src8++);
    555 
    556 			src = (u32 *) src8;
    557 		}
    558 
    559 		if (copy_to_user(buf, buffer, c)) {
    560 			err = -EFAULT;
    561 			break;
    562 		}
    563 		*ppos += c;
    564 		buf += c;
    565 		cnt += c;
    566 		count -= c;
    567 	}
    568 
    569 	kfree(buffer);
    570 	return (err) ? err : cnt;
    571 }
    572 
    573 static ssize_t
    574 fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
    575 {
    576 	unsigned long p = *ppos;
    577 	struct inode *inode = file->f_dentry->d_inode;
    578 	int fbidx = iminor(inode);
    579 	struct fb_info *info = registered_fb[fbidx];
    580 	u32 *buffer, *dst, *src;
    581 	int c, i, cnt = 0, err;
    582 	unsigned long total_size;
    583 
    584 	if (!info || !info->screen_base)
    585 		return -ENODEV;
    586 
    587 	if (info->state != FBINFO_STATE_RUNNING)
    588 		return -EPERM;
    589 
    590 	if (info->fbops->fb_write)
    591 		return info->fbops->fb_write(file, buf, count, ppos);
    592 	
    593 	total_size = info->screen_size;
    594 	if (total_size == 0)
    595 		total_size = info->fix.smem_len;
    596 
    597 	if (p > total_size)
    598 	    return -ENOSPC;
    599 	if (count >= total_size)
    600 	    count = total_size;
    601 	err = 0;
    602 	if (count + p > total_size) {
    603 	    count = total_size - p;
    604 	    err = -ENOSPC;
    605 	}
    606 	cnt = 0;
    607 	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
    608 			 GFP_KERNEL);
    609 	if (!buffer)
    610 		return -ENOMEM;
    611 
    612 	dst = (u32 *) (info->screen_base + p);
    613 
    614 	if (info->fbops->fb_sync)
    615 		info->fbops->fb_sync(info);
    616 
    617 	while (count) {
    618 		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
    619 		src = buffer;
    620 		if (copy_from_user(src, buf, c)) {
    621 			err = -EFAULT;
    622 			break;
    623 		}
    624 		for (i = c >> 2; i--; )
    625 			fb_writel(*src++, dst++);
    626 		if (c & 3) {
    627 			u8 *src8 = (u8 *) src;
    628 			u8 *dst8 = (u8 *) dst;
    629 
    630 			for (i = c & 3; i--; )
    631 				fb_writeb(*src8++, dst8++);
    632 
    633 			dst = (u32 *) dst8;
    634 		}
    635 		*ppos += c;
    636 		buf += c;
    637 		cnt += c;
    638 		count -= c;
    639 	}
    640 	kfree(buffer);
    641 
    642 	return (err) ? err : cnt;
    643 }
    644 
    645 #ifdef CONFIG_KMOD
    646 static void try_to_load(int fb)
    647 {
    648 	request_module("fb%d", fb);
    649 }
    650 #endif /* CONFIG_KMOD */
    651 
    652 void
    653 fb_load_cursor_image(struct fb_info *info)
    654 {
    655 	unsigned int width = (info->cursor.image.width + 7) >> 3;
    656 	u8 *data = (u8 *) info->cursor.image.data;
    657 
    658 	if (info->sprite.outbuf)
    659 	    info->sprite.outbuf(info, info->sprite.addr, data, width);
    660 	else
    661 	    memcpy(info->sprite.addr, data, width);
    662 }
    663 
    664 int
    665 fb_cursor(struct fb_info *info, struct fb_cursor_user __user *sprite)
    666 {
    667 	struct fb_cursor_user cursor_user;
    668 	struct fb_cursor cursor;
    669 	char *data = NULL, *mask = NULL, *info_mask = NULL;
    670 	u16 *red = NULL, *green = NULL, *blue = NULL, *transp = NULL;
    671 	int err = -EINVAL;
    672 	
    673 	if (copy_from_user(&cursor_user, sprite, sizeof(struct fb_cursor_user)))
    674 		return -EFAULT;
    675 
    676 	memcpy(&cursor, &cursor_user, sizeof(cursor_user));
    677 	cursor.mask = info->cursor.mask;
    678 	cursor.image.data = info->cursor.image.data;
    679 	cursor.image.cmap.red = info->cursor.image.cmap.red;
    680 	cursor.image.cmap.green = info->cursor.image.cmap.green;
    681 	cursor.image.cmap.blue = info->cursor.image.cmap.blue;
    682 	cursor.image.cmap.transp = info->cursor.image.cmap.transp;
    683 	cursor.data = NULL;
    684 
    685 	if (cursor.set & FB_CUR_SETCUR)
    686 		info->cursor.enable = 1;
    687 	
    688 	if (cursor.set & FB_CUR_SETCMAP) {
    689 		unsigned len = cursor.image.cmap.len;
    690 		if ((int)len <= 0)
    691 			goto out;
    692 		len *= 2;
    693 		err = -ENOMEM;
    694 		red = kmalloc(len, GFP_USER);
    695 		green = kmalloc(len, GFP_USER);
    696 		blue = kmalloc(len, GFP_USER);
    697 		if (!red || !green || !blue)
    698 			goto out;
    699 		if (cursor_user.image.cmap.transp) {
    700 			transp = kmalloc(len, GFP_USER);
    701 			if (!transp)
    702 				goto out;
    703 		}
    704 		err = -EFAULT;
    705 		if (copy_from_user(red, cursor_user.image.cmap.red, len))
    706 			goto out;
    707 		if (copy_from_user(green, cursor_user.image.cmap.green, len))
    708 			goto out;
    709 		if (copy_from_user(blue, cursor_user.image.cmap.blue, len))
    710 			goto out;
    711 		if (transp) {
    712 			if (copy_from_user(transp,
    713 					   cursor_user.image.cmap.transp, len))
    714 				goto out;
    715 		}
    716 		cursor.image.cmap.red = red;
    717 		cursor.image.cmap.green = green;
    718 		cursor.image.cmap.blue = blue;
    719 		cursor.image.cmap.transp = transp;
    720 	}
    721 	
    722 	if (cursor.set & FB_CUR_SETSHAPE) {
    723 		int size = ((cursor.image.width + 7) >> 3) * cursor.image.height;		
    724 
    725 		if ((cursor.image.height != info->cursor.image.height) ||
    726 		    (cursor.image.width != info->cursor.image.width))
    727 			cursor.set |= FB_CUR_SETSIZE;
    728 		
    729 		err = -ENOMEM;
    730 		data = kmalloc(size, GFP_USER);
    731 		mask = kmalloc(size, GFP_USER);
    732 		if (!mask || !data)
    733 			goto out;
    734 		
    735 		err = -EFAULT;
    736 		if (copy_from_user(data, cursor_user.image.data, size) ||
    737 		    copy_from_user(mask, cursor_user.mask, size))
    738 			goto out;
    739 		
    740 		cursor.image.data = data;
    741 		cursor.mask = mask;
    742 		info_mask = (char *) info->cursor.mask;
    743 		info->cursor.mask = mask;
    744 	}
    745 	info->cursor.set = cursor.set;
    746 	info->cursor.rop = cursor.rop;
    747 	err = info->fbops->fb_cursor(info, &cursor);
    748 out:
    749 	kfree(data);
    750 	kfree(mask);
    751 	kfree(red);
    752 	kfree(green);
    753 	kfree(blue);
    754 	kfree(transp);
    755 	if (info_mask)
    756 		info->cursor.mask = info_mask;
    757 	return err;
    758 }
    759 
    760 int
    761 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
    762 {
    763         int xoffset = var->xoffset;
    764         int yoffset = var->yoffset;
    765         int err;
    766 
    767         if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display ||
    768             xoffset + info->var.xres > info->var.xres_virtual ||
    769             yoffset + info->var.yres > info->var.yres_virtual)
    770                 return -EINVAL;
    771 	if ((err = info->fbops->fb_pan_display(var, info)))
    772 		return err;
    773         info->var.xoffset = var->xoffset;
    774         info->var.yoffset = var->yoffset;
    775         if (var->vmode & FB_VMODE_YWRAP)
    776                 info->var.vmode |= FB_VMODE_YWRAP;
    777         else
    778                 info->var.vmode &= ~FB_VMODE_YWRAP;
    779         return 0;
    780 }
    781 
    782 int
    783 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
    784 {
    785 	int err;
    786 
    787 	if (var->activate & FB_ACTIVATE_INV_MODE) {
    788 		struct fb_videomode mode1, mode2;
    789 		int ret = 0;
    790 
    791 		fb_var_to_videomode(&mode1, var);
    792 		fb_var_to_videomode(&mode2, &info->var);
    793 		/* make sure we don't delete the videomode of current var */
    794 		ret = fb_mode_is_equal(&mode1, &mode2);
    795 
    796 		if (!ret) {
    797 		    struct fb_event event;
    798 
    799 		    event.info = info;
    800 		    event.data = &mode1;
    801 		    ret = notifier_call_chain(&fb_notifier_list,
    802 					      FB_EVENT_MODE_DELETE, &event);
    803 		}
    804 
    805 		if (!ret)
    806 		    fb_delete_videomode(&mode1, &info->modelist);
    807 
    808 		return ret;
    809 	}
    810 
    811 	if ((var->activate & FB_ACTIVATE_FORCE) ||
    812 	    memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
    813 		if (!info->fbops->fb_check_var) {
    814 			*var = info->var;
    815 			return 0;
    816 		}
    817 
    818 		if ((err = info->fbops->fb_check_var(var, info)))
    819 			return err;
    820 
    821 		if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
    822 			struct fb_videomode mode;
    823 			info->var = *var;
    824 
    825 			if (info->fbops->fb_set_par)
    826 				info->fbops->fb_set_par(info);
    827 
    828 			fb_pan_display(info, &info->var);
    829 
    830 			fb_set_cmap(&info->cmap, info);
    831 
    832 			fb_var_to_videomode(&mode, &info->var);
    833 			fb_add_videomode(&mode, &info->modelist);
    834 
    835 			if (info->flags & FBINFO_MISC_MODECHANGEUSER) {
    836 				struct fb_event event;
    837 
    838 				info->flags &= ~FBINFO_MISC_MODECHANGEUSER;
    839 				event.info = info;
    840 				notifier_call_chain(&fb_notifier_list,
    841 						    FB_EVENT_MODE_CHANGE, &event);
    842 			}
    843 		}
    844 	}
    845 	return 0;
    846 }
    847 
    848 int
    849 fb_blank(struct fb_info *info, int blank)
    850 {	
    851 	/* ??? Variable sized stack allocation.  */
    852 	u16 black[info->cmap.len];
    853 	struct fb_cmap cmap;
    854 	
    855 	if (info->fbops->fb_blank && !info->fbops->fb_blank(blank, info))
    856 		return 0;
    857 	if (blank) { 
    858 		memset(black, 0, info->cmap.len * sizeof(u16));
    859 		cmap.red = cmap.green = cmap.blue = black;
    860 		cmap.transp = info->cmap.transp ? black : NULL;
    861 		cmap.start = info->cmap.start;
    862 		cmap.len = info->cmap.len;
    863 	} else
    864 		cmap = info->cmap;
    865 	return fb_set_cmap(&cmap, info);
    866 }
    867 
    868 static int 
    869 fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
    870 	 unsigned long arg)
    871 {
    872 	int fbidx = iminor(inode);
    873 	struct fb_info *info = registered_fb[fbidx];
    874 	struct fb_ops *fb = info->fbops;
    875 	struct fb_var_screeninfo var;
    876 	struct fb_fix_screeninfo fix;
    877 	struct fb_con2fbmap con2fb;
    878 	struct fb_cmap_user cmap;
    879 	struct fb_event event;
    880 	void __user *argp = (void __user *)arg;
    881 	int i;
    882 	
    883 	if (!fb)
    884 		return -ENODEV;
    885 	switch (cmd) {
    886 	case FBIOGET_VSCREENINFO:
    887 		return copy_to_user(argp, &info->var,
    888 				    sizeof(var)) ? -EFAULT : 0;
    889 	case FBIOPUT_VSCREENINFO:
    890 		if (copy_from_user(&var, argp, sizeof(var)))
    891 			return -EFAULT;
    892 		acquire_console_sem();
    893 		info->flags |= FBINFO_MISC_MODECHANGEUSER;
    894 		i = fb_set_var(info, &var);
    895 		info->flags &= ~FBINFO_MISC_MODECHANGEUSER;
    896 		release_console_sem();
    897 		if (i) return i;
    898 		if (copy_to_user(argp, &var, sizeof(var)))
    899 			return -EFAULT;
    900 		return 0;
    901 	case FBIOGET_FSCREENINFO:
    902 		return copy_to_user(argp, &info->fix,
    903 				    sizeof(fix)) ? -EFAULT : 0;
    904 	case FBIOPUTCMAP:
    905 		if (copy_from_user(&cmap, argp, sizeof(cmap)))
    906 			return -EFAULT;
    907 		return (fb_set_user_cmap(&cmap, info));
    908 	case FBIOGETCMAP:
    909 		if (copy_from_user(&cmap, argp, sizeof(cmap)))
    910 			return -EFAULT;
    911 		return fb_cmap_to_user(&info->cmap, &cmap);
    912 	case FBIOPAN_DISPLAY:
    913 		if (copy_from_user(&var, argp, sizeof(var)))
    914 			return -EFAULT;
    915 		acquire_console_sem();
    916 		i = fb_pan_display(info, &var);
    917 		release_console_sem();
    918 		if (i)
    919 			return i;
    920 		if (copy_to_user(argp, &var, sizeof(var)))
    921 			return -EFAULT;
    922 		return 0;
    923 	case FBIO_CURSOR:
    924 		acquire_console_sem();
    925 		i = fb_cursor(info, argp);
    926 		release_console_sem();
    927 		return i;
    928 	case FBIOGET_CON2FBMAP:
    929 		if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
    930 			return -EFAULT;
    931 		if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
    932 		    return -EINVAL;
    933 		con2fb.framebuffer = -1;
    934 		event.info = info;
    935 		event.data = &con2fb;
    936 		notifier_call_chain(&fb_notifier_list,
    937 				    FB_EVENT_GET_CONSOLE_MAP, &event);
    938 		return copy_to_user(argp, &con2fb,
    939 				    sizeof(con2fb)) ? -EFAULT : 0;
    940 	case FBIOPUT_CON2FBMAP:
    941 		if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
    942 			return - EFAULT;
    943 		if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
    944 		    return -EINVAL;
    945 		if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
    946 		    return -EINVAL;
    947 #ifdef CONFIG_KMOD
    948 		if (!registered_fb[con2fb.framebuffer])
    949 		    try_to_load(con2fb.framebuffer);
    950 #endif /* CONFIG_KMOD */
    951 		if (!registered_fb[con2fb.framebuffer])
    952 		    return -EINVAL;
    953 		if (con2fb.console > 0 && con2fb.console < MAX_NR_CONSOLES) {
    954 			event.info = info;
    955 			event.data = &con2fb;
    956 			return notifier_call_chain(&fb_notifier_list,
    957 						   FB_EVENT_SET_CONSOLE_MAP,
    958 						   &event);
    959 		}
    960 		return -EINVAL;
    961 	case FBIOBLANK:
    962 		acquire_console_sem();
    963 		i = fb_blank(info, arg);
    964 		release_console_sem();
    965 		return i;
    966 
    967 #ifdef CONFIG_FB_UI
    968 	case FBIO_UI_OPEN: {
    969                 if (access_ok (VERIFY_READ, (char*) arg, sizeof(struct fbui_openparams))) 
    970 			return fbui_open (info, (struct fbui_openparams*) arg);
    971                 else
    972 			return -EFAULT;
    973 	}
    974 
    975 	case FBIO_UI_CLOSE:
    976 		return fbui_close (info, arg);
    977 
    978         case FBIO_UI_EXEC: {
    979                 short win_id=-1;
    980                 short nwords=0;
    981                 short *ptr=(short*) arg;
    982                 if (access_ok (VERIFY_READ, (char*) arg, 4)) {
    983                         if (get_user (win_id, ptr))
    984 				return -EFAULT;
    985 			if (win_id < 0 || win_id >= FBUI_MAXWINDOWSPERVC*FBUI_MAXCONSOLES)
    986 				return FBUI_ERR_BADWIN;
    987 			ptr++;
    988                         if (get_user (nwords, ptr))
    989 				return -EFAULT;
    990 			arg += 4;
    991 			if (access_ok (VERIFY_READ, (char*) (arg), 2*nwords)) 
    992 				return fbui_exec (info, win_id, nwords, 
    993 					(unsigned char*) (arg));
    994 			else
    995 				return -EFAULT;
    996                 }
    997                 else
    998 			return -EFAULT;
    999         }
   1000 
   1001 	case FBIO_UI_CONTROL:
   1002                 if (access_ok (VERIFY_READ, (char*) arg, sizeof(struct fbui_ctrlparams)))
   1003 		{
   1004 			struct fbui_ctrlparams ctl;
   1005 			if (!copy_from_user (&ctl, (void*)arg, sizeof(struct fbui_ctrlparams))){
   1006 				return fbui_control (info, &ctl);
   1007 			} else {
   1008 				return -EFAULT;
   1009 			}
   1010 		} else {
   1011 			return -EFAULT;
   1012 }
   1013 #endif
   1014 
   1015 	default:
   1016 		if (fb->fb_ioctl == NULL)
   1017 			return -EINVAL;
   1018 		return fb->fb_ioctl(inode, file, cmd, arg, info);
   1019 	}
   1020 }
   1021 
   1022 static int 
   1023 fb_mmap(struct file *file, struct vm_area_struct * vma)
   1024 {
   1025 	int fbidx = iminor(file->f_dentry->d_inode);
   1026 	struct fb_info *info = registered_fb[fbidx];
   1027 	struct fb_ops *fb = info->fbops;
   1028 	unsigned long off;
   1029 #if !defined(__sparc__) || defined(__sparc_v9__)
   1030 	unsigned long start;
   1031 	u32 len;
   1032 #endif
   1033 
   1034 	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
   1035 		return -EINVAL;
   1036 	off = vma->vm_pgoff << PAGE_SHIFT;
   1037 	if (!fb)
   1038 		return -ENODEV;
   1039 	if (fb->fb_mmap) {
   1040 		int res;
   1041 		lock_kernel();
   1042 		res = fb->fb_mmap(info, file, vma);
   1043 		unlock_kernel();
   1044 		return res;
   1045 	}
   1046 
   1047 #if defined(__sparc__) && !defined(__sparc_v9__)
   1048 	/* Should never get here, all fb drivers should have their own
   1049 	   mmap routines */
   1050 	return -EINVAL;
   1051 #else
   1052 	/* !sparc32... */
   1053 	lock_kernel();
   1054 
   1055 	/* frame buffer memory */
   1056 	start = info->fix.smem_start;
   1057 	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
   1058 	if (off >= len) {
   1059 		/* memory mapped io */
   1060 		off -= len;
   1061 		if (info->var.accel_flags) {
   1062 			unlock_kernel();
   1063 			return -EINVAL;
   1064 		}
   1065 		start = info->fix.mmio_start;
   1066 		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
   1067 	}
   1068 	unlock_kernel();
   1069 	start &= PAGE_MASK;
   1070 	if ((vma->vm_end - vma->vm_start + off) > len)
   1071 		return -EINVAL;
   1072 	off += start;
   1073 	vma->vm_pgoff = off >> PAGE_SHIFT;
   1074 	/* This is an IO map - tell maydump to skip this VMA */
   1075 	vma->vm_flags |= VM_IO;
   1076 #if defined(__sparc_v9__)
   1077 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
   1078 	if (io_remap_page_range(vma, vma->vm_start, off,
   1079 				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
   1080 		return -EAGAIN;
   1081 #else
   1082 #if defined(__mc68000__)
   1083 #if defined(CONFIG_SUN3)
   1084 	pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
   1085 #elif defined(CONFIG_MMU)
   1086 	if (CPU_IS_020_OR_030)
   1087 		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
   1088 	if (CPU_IS_040_OR_060) {
   1089 		pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
   1090 		/* Use no-cache mode, serialized */
   1091 		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
   1092 	}
   1093 #endif
   1094 #elif defined(__powerpc__)
   1095 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
   1096 #elif defined(__alpha__)
   1097 	/* Caching is off in the I/O space quadrant by design.  */
   1098 #elif defined(__i386__) || defined(__x86_64__)
   1099 	if (boot_cpu_data.x86 > 3)
   1100 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
   1101 #elif defined(__mips__)
   1102 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
   1103 #elif defined(__hppa__)
   1104 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
   1105 #elif defined(__ia64__) || defined(__arm__) || defined(__sh__)
   1106 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
   1107 #else
   1108 #warning What do we have to do here??
   1109 #endif
   1110 	if (io_remap_page_range(vma, vma->vm_start, off,
   1111 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
   1112 		return -EAGAIN;
   1113 #endif /* !__sparc_v9__ */
   1114 	return 0;
   1115 #endif /* !sparc32 */
   1116 }
   1117 
   1118 static int
   1119 fb_open(struct inode *inode, struct file *file)
   1120 {
   1121 	int fbidx = iminor(inode);
   1122 	struct fb_info *info;
   1123 	int res = 0;
   1124 
   1125 	if (fbidx >= FB_MAX)
   1126 		return -ENODEV;
   1127 #ifdef CONFIG_KMOD
   1128 	if (!(info = registered_fb[fbidx]))
   1129 		try_to_load(fbidx);
   1130 #endif /* CONFIG_KMOD */
   1131 	if (!(info = registered_fb[fbidx]))
   1132 		return -ENODEV;
   1133 	if (!try_module_get(info->fbops->owner))
   1134 		return -ENODEV;
   1135 	if (info->fbops->fb_open) {
   1136 		res = info->fbops->fb_open(info,1);
   1137 		if (res)
   1138 			module_put(info->fbops->owner);
   1139 	}
   1140 	return res;
   1141 }
   1142 
   1143 static int 
   1144 fb_release(struct inode *inode, struct file *file)
   1145 {
   1146 	int fbidx = iminor(inode);
   1147 	struct fb_info *info;
   1148 
   1149 	lock_kernel();
   1150 	info = registered_fb[fbidx];
   1151 	if (info->fbops->fb_release)
   1152 		info->fbops->fb_release(info,1);
   1153 	module_put(info->fbops->owner);
   1154 	unlock_kernel();
   1155 	return 0;
   1156 }
   1157 
   1158 static struct file_operations fb_fops = {
   1159 	.owner =	THIS_MODULE,
   1160 	.read =		fb_read,
   1161 	.write =	fb_write,
   1162 	.ioctl =	fb_ioctl,
   1163 	.mmap =		fb_mmap,
   1164 	.open =		fb_open,
   1165 	.release =	fb_release,
   1166 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
   1167 	.get_unmapped_area = get_fb_unmapped_area,
   1168 #endif
   1169 };
   1170 
   1171 static struct class_simple *fb_class;
   1172 
   1173 /**
   1174  *	register_framebuffer - registers a frame buffer device
   1175  *	@fb_info: frame buffer info structure
   1176  *
   1177  *	Registers a frame buffer device @fb_info.
   1178  *
   1179  *	Returns negative errno on error, or zero for success.
   1180  *
   1181  */
   1182 
   1183 int
   1184 register_framebuffer(struct fb_info *fb_info)
   1185 {
   1186 	int i;
   1187 	struct class_device *c;
   1188 	struct fb_event event;
   1189 
   1190 	if (num_registered_fb == FB_MAX)
   1191 		return -ENXIO;
   1192 	num_registered_fb++;
   1193 	for (i = 0 ; i < FB_MAX; i++)
   1194 		if (!registered_fb[i])
   1195 			break;
   1196 	fb_info->node = i;
   1197 
   1198 	c = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
   1199 	if (IS_ERR(c)) {
   1200 		/* Not fatal */
   1201 		printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(c));
   1202 	}
   1203 	
   1204 	if (fb_info->pixmap.addr == NULL) {
   1205 		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
   1206 		if (fb_info->pixmap.addr) {
   1207 			fb_info->pixmap.size = FBPIXMAPSIZE;
   1208 			fb_info->pixmap.buf_align = 1;
   1209 			fb_info->pixmap.scan_align = 1;
   1210 			fb_info->pixmap.access_align = 4;
   1211 			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
   1212 		}
   1213 	}	
   1214 	fb_info->pixmap.offset = 0;
   1215 
   1216 	if (fb_info->sprite.addr == NULL) {
   1217 		fb_info->sprite.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
   1218 		if (fb_info->sprite.addr) {
   1219 			fb_info->sprite.size = FBPIXMAPSIZE;
   1220 			fb_info->sprite.buf_align = 1;
   1221 			fb_info->sprite.scan_align = 1;
   1222 			fb_info->sprite.access_align = 4;
   1223 			fb_info->sprite.flags = FB_PIXMAP_DEFAULT;
   1224 		}
   1225 	}
   1226 	fb_info->sprite.offset = 0;
   1227 
   1228 	if (!fb_info->modelist.prev ||
   1229 	    !fb_info->modelist.next ||
   1230 	    list_empty(&fb_info->modelist)) {
   1231 	        struct fb_videomode mode;
   1232 
   1233 		INIT_LIST_HEAD(&fb_info->modelist);
   1234 		fb_var_to_videomode(&mode, &fb_info->var);
   1235 		fb_add_videomode(&mode, &fb_info->modelist);
   1236 	}
   1237 
   1238 	registered_fb[i] = fb_info;
   1239 
   1240 	devfs_mk_cdev(MKDEV(FB_MAJOR, i),
   1241 			S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
   1242 	event.info = fb_info;
   1243 	notifier_call_chain(&fb_notifier_list,
   1244 			    FB_EVENT_FB_REGISTERED, &event);
   1245 	return 0;
   1246 }
   1247 
   1248 
   1249 /**
   1250  *	unregister_framebuffer - releases a frame buffer device
   1251  *	@fb_info: frame buffer info structure
   1252  *
   1253  *	Unregisters a frame buffer device @fb_info.
   1254  *
   1255  *	Returns negative errno on error, or zero for success.
   1256  *
   1257  */
   1258 
   1259 int
   1260 unregister_framebuffer(struct fb_info *fb_info)
   1261 {
   1262 	int i;
   1263 
   1264 	i = fb_info->node;
   1265 	if (!registered_fb[i])
   1266 		return -EINVAL;
   1267 	devfs_remove("fb/%d", i);
   1268 
   1269 	if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
   1270 		kfree(fb_info->pixmap.addr);
   1271 	if (fb_info->sprite.addr && (fb_info->sprite.flags & FB_PIXMAP_DEFAULT))
   1272 		kfree(fb_info->sprite.addr);
   1273 	fb_destroy_modelist(&fb_info->modelist);
   1274 	registered_fb[i]=NULL;
   1275 	num_registered_fb--;
   1276 	class_simple_device_remove(MKDEV(FB_MAJOR, i));
   1277 	return 0;
   1278 }
   1279 
   1280 /**
   1281  *	fb_register_client - register a client notifier
   1282  *	@nb: notifier block to callback on events
   1283  */
   1284 int fb_register_client(struct notifier_block *nb)
   1285 {
   1286 	return notifier_chain_register(&fb_notifier_list, nb);
   1287 }
   1288 
   1289 /**
   1290  *	fb_unregister_client - unregister a client notifier
   1291  *	@nb: notifier block to callback on events
   1292  */
   1293 int fb_unregister_client(struct notifier_block *nb)
   1294 {
   1295 	return notifier_chain_unregister(&fb_notifier_list, nb);
   1296 }
   1297 
   1298 /**
   1299  *	fb_set_suspend - low level driver signals suspend
   1300  *	@info: framebuffer affected
   1301  *	@state: 0 = resuming, !=0 = suspending
   1302  *
   1303  *	This is meant to be used by low level drivers to
   1304  * 	signal suspend/resume to the core & clients.
   1305  *	It must be called with the console semaphore held
   1306  */
   1307 void fb_set_suspend(struct fb_info *info, int state)
   1308 {
   1309 	struct fb_event event;
   1310 
   1311 	event.info = info;
   1312 	if (state) {
   1313 		notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event);
   1314 		info->state = FBINFO_STATE_SUSPENDED;
   1315 	} else {
   1316 		info->state = FBINFO_STATE_RUNNING;
   1317 		notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event);
   1318 	}
   1319 }
   1320 
   1321 /**
   1322  *	fbmem_init - init frame buffer subsystem
   1323  *
   1324  *	Initialize the frame buffer subsystem.
   1325  *
   1326  *	NOTE: This function is _only_ to be called by drivers/char/mem.c.
   1327  *
   1328  */
   1329 
   1330 int __init
   1331 fbmem_init(void)
   1332 {
   1333 	create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
   1334 
   1335 	devfs_mk_dir("fb");
   1336 	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
   1337 		printk("unable to get major %d for fb devs\n", FB_MAJOR);
   1338 
   1339 	fb_class = class_simple_create(THIS_MODULE, "graphics");
   1340 	if (IS_ERR(fb_class)) {
   1341 		printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
   1342 		fb_class = NULL;
   1343 	}
   1344 	return 0;
   1345 }
   1346 module_init(fbmem_init);
   1347 
   1348 #define NR_FB_DRIVERS 64
   1349 static char *video_options[NR_FB_DRIVERS];
   1350 static int ofonly;
   1351 
   1352 /**
   1353  * fb_get_options - get kernel boot parameters
   1354  * @name - framebuffer name as it would appear in
   1355  *         the boot parameter line
   1356  *         (video=<name>:<options>)
   1357  *
   1358  * NOTE: Needed to maintain backwards compatibility
   1359  */
   1360 int fb_get_options(char *name, char **option)
   1361 {
   1362 	char *opt, *options = NULL;
   1363 	int opt_len, retval = 0;
   1364 	int name_len = strlen(name), i;
   1365 
   1366 	if (name_len && ofonly && strncmp(name, "offb", 4))
   1367 		retval = 1;
   1368 
   1369 	if (name_len && !retval) {
   1370 		for (i = 0; i < NR_FB_DRIVERS; i++) {
   1371 			if (video_options[i] == NULL)
   1372 				continue;
   1373 			opt_len = strlen(video_options[i]);
   1374 			if (!opt_len)
   1375 				continue;
   1376 			opt = video_options[i];
   1377 			if (!strncmp(name, opt, name_len) &&
   1378 			    opt[name_len] == ':')
   1379 				options = opt + name_len + 1;
   1380 		}
   1381 	}
   1382 	if (options && !strncmp(options, "off", 3))
   1383 		retval = 1;
   1384 
   1385 	if (option)
   1386 		*option = options;
   1387 
   1388 	return retval;
   1389 }
   1390 
   1391 /**
   1392  *	video_setup - process command line options
   1393  *	@options: string of options
   1394  *
   1395  *	Process command line options for frame buffer subsystem.
   1396  *
   1397  *	NOTE: This function is a __setup and __init function.
   1398  *            It only stores the options.  Drivers have to call
   1399  *            fb_get_options() as necessary.
   1400  *
   1401  *	Returns zero.
   1402  *
   1403  */
   1404 
   1405 int __init video_setup(char *options)
   1406 {
   1407 	int i;
   1408 
   1409 	if (!options || !*options)
   1410 		return 0;
   1411 
   1412 	for (i = 0; i < NR_FB_DRIVERS; i++) {
   1413 		if (!strncmp(options, "ofonly", 6))
   1414 			ofonly = 1;
   1415 		if (video_options[i] == NULL) {
   1416 			video_options[i] = options;
   1417 			break;
   1418 		}
   1419 	}
   1420 
   1421 	return 0;
   1422 }
   1423 __setup("video=", video_setup);
   1424 
   1425     /*
   1426      *  Visible symbols for modules
   1427      */
   1428 
   1429 EXPORT_SYMBOL(register_framebuffer);
   1430 EXPORT_SYMBOL(unregister_framebuffer);
   1431 EXPORT_SYMBOL(num_registered_fb);
   1432 EXPORT_SYMBOL(registered_fb);
   1433 EXPORT_SYMBOL(fb_prepare_logo);
   1434 EXPORT_SYMBOL(fb_show_logo);
   1435 EXPORT_SYMBOL(fb_set_var);
   1436 EXPORT_SYMBOL(fb_blank);
   1437 EXPORT_SYMBOL(fb_pan_display);
   1438 EXPORT_SYMBOL(fb_get_buffer_offset);
   1439 EXPORT_SYMBOL(fb_iomove_buf_unaligned);
   1440 EXPORT_SYMBOL(fb_iomove_buf_aligned);
   1441 EXPORT_SYMBOL(fb_sysmove_buf_unaligned);
   1442 EXPORT_SYMBOL(fb_sysmove_buf_aligned);
   1443 EXPORT_SYMBOL(fb_load_cursor_image);
   1444 EXPORT_SYMBOL(fb_set_suspend);
   1445 EXPORT_SYMBOL(fb_register_client);
   1446 EXPORT_SYMBOL(fb_unregister_client);
   1447 EXPORT_SYMBOL(fb_get_options);
   1448 
   1449 MODULE_LICENSE("GPL");

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.