Blame view

drivers/video/fbmem.c 45.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   *  linux/drivers/video/fbmem.c
   *
   *  Copyright (C) 1994 Martin Schaller
   *
   *	2001 - Documented with DocBook
   *	- Brad Douglas <brad@neruo.com>
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file COPYING in the main directory of this archive
   * for more details.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/module.h>
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
14
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/types.h>
  #include <linux/errno.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
  #include <linux/kernel.h>
  #include <linux/major.h>
  #include <linux/slab.h>
  #include <linux/mm.h>
  #include <linux/mman.h>
a8f340e39   Jon Smirl   [PATCH] vt: Remov...
22
  #include <linux/vt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  #include <linux/init.h>
  #include <linux/linux_logo.h>
  #include <linux/proc_fs.h>
0aa163418   Alexey Dobriyan   fb: convert /proc...
26
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  #include <linux/console.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <linux/kmod.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  #include <linux/device.h>
  #include <linux/efi.h>
10eb2659c   Antonino A. Daplas   fbdev: move arch-...
32
  #include <linux/fb.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

10eb2659c   Antonino A. Daplas   fbdev: move arch-...
34
  #include <asm/fb.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
  
      /*
       *  Frame buffer device initialization and setup routines
       */
  
  #define FBPIXMAPSIZE	(1024 * 8)
698b36827   Linus Torvalds   fbcon: add lifeti...
42
  static DEFINE_MUTEX(registration_lock);
0128beeee   Helge Deller   [PATCH] constify ...
43
44
  struct fb_info *registered_fb[FB_MAX] __read_mostly;
  int num_registered_fb __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

698b36827   Linus Torvalds   fbcon: add lifeti...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  static struct fb_info *get_fb_info(unsigned int idx)
  {
  	struct fb_info *fb_info;
  
  	if (idx >= FB_MAX)
  		return ERR_PTR(-ENODEV);
  
  	mutex_lock(&registration_lock);
  	fb_info = registered_fb[idx];
  	if (fb_info)
  		atomic_inc(&fb_info->count);
  	mutex_unlock(&registration_lock);
  
  	return fb_info;
  }
  
  static void put_fb_info(struct fb_info *fb_info)
  {
  	if (!atomic_dec_and_test(&fb_info->count))
  		return;
  	if (fb_info->fbops->fb_destroy)
  		fb_info->fbops->fb_destroy(fb_info);
  }
6a7f2829b   Andrew Morton   fbdev: uninline l...
69
70
71
72
73
74
75
76
77
78
  int lock_fb_info(struct fb_info *info)
  {
  	mutex_lock(&info->lock);
  	if (!info->fbops) {
  		mutex_unlock(&info->lock);
  		return 0;
  	}
  	return 1;
  }
  EXPORT_SYMBOL(lock_fb_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
  /*
   * Helpers
   */
b8c909454   Antonino A. Daplas   [PATCH] fbdev: Fi...
82
83
  int fb_get_color_depth(struct fb_var_screeninfo *var,
  		       struct fb_fix_screeninfo *fix)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
b8c909454   Antonino A. Daplas   [PATCH] fbdev: Fi...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  	int depth = 0;
  
  	if (fix->visual == FB_VISUAL_MONO01 ||
  	    fix->visual == FB_VISUAL_MONO10)
  		depth = 1;
  	else {
  		if (var->green.length == var->blue.length &&
  		    var->green.length == var->red.length &&
  		    var->green.offset == var->blue.offset &&
  		    var->green.offset == var->red.offset)
  			depth = var->green.length;
  		else
  			depth = var->green.length + var->red.length +
  				var->blue.length;
  	}
  
  	return depth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
  }
  EXPORT_SYMBOL(fb_get_color_depth);
  
  /*
f5a9951c9   James Simmons   [PATCH] fbdev: io...
106
   * Data padding functions.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
   */
f1ab5dac2   James Simmons   [PATCH] fbdev: st...
108
  void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  {
829e79b68   Antonino A. Daplas   [PATCH] fbcon: Br...
110
  	__fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  }
f1ab5dac2   James Simmons   [PATCH] fbdev: st...
112
  EXPORT_SYMBOL(fb_pad_aligned_buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113

f1ab5dac2   James Simmons   [PATCH] fbdev: st...
114
115
  void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height,
  				u32 shift_high, u32 shift_low, u32 mod)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  {
  	u8 mask = (u8) (0xfff << shift_high), tmp;
  	int i, j;
  
  	for (i = height; i--; ) {
  		for (j = 0; j < idx; j++) {
  			tmp = dst[j];
  			tmp &= mask;
  			tmp |= *src >> shift_low;
  			dst[j] = tmp;
  			tmp = *src << shift_high;
  			dst[j+1] = tmp;
  			src++;
  		}
  		tmp = dst[idx];
  		tmp &= mask;
  		tmp |= *src >> shift_low;
  		dst[idx] = tmp;
  		if (shift_high < mod) {
  			tmp = *src << shift_high;
  			dst[idx+1] = tmp;
  		}
  		src++;
  		dst += d_pitch;
  	}
  }
f1ab5dac2   James Simmons   [PATCH] fbdev: st...
142
  EXPORT_SYMBOL(fb_pad_unaligned_buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  
  /*
   * we need to lock this section since fb_cursor
   * may use fb_imageblit()
   */
  char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size)
  {
  	u32 align = buf->buf_align - 1, offset;
  	char *addr = buf->addr;
  
  	/* If IO mapped, we need to sync before access, no sharing of
  	 * the pixmap is done
  	 */
  	if (buf->flags & FB_PIXMAP_IO) {
  		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
  			info->fbops->fb_sync(info);
  		return addr;
  	}
  
  	/* See if we fit in the remaining pixmap space */
  	offset = buf->offset + align;
  	offset &= ~align;
  	if (offset + size > buf->size) {
  		/* We do not fit. In order to be able to re-use the buffer,
  		 * we must ensure no asynchronous DMA'ing or whatever operation
  		 * is in progress, we sync for that.
  		 */
  		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
  			info->fbops->fb_sync(info);
  		offset = 0;
  	}
  	buf->offset = offset + size;
  	addr += offset;
  
  	return addr;
  }
  
  #ifdef CONFIG_LOGO
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  
  static inline unsigned safe_shift(unsigned d, int n)
  {
  	return n < 0 ? d >> -n : d << n;
  }
  
  static void fb_set_logocmap(struct fb_info *info,
  				   const struct linux_logo *logo)
  {
  	struct fb_cmap palette_cmap;
  	u16 palette_green[16];
  	u16 palette_blue[16];
  	u16 palette_red[16];
  	int i, j, n;
  	const unsigned char *clut = logo->clut;
  
  	palette_cmap.start = 0;
  	palette_cmap.len = 16;
  	palette_cmap.red = palette_red;
  	palette_cmap.green = palette_green;
  	palette_cmap.blue = palette_blue;
  	palette_cmap.transp = NULL;
  
  	for (i = 0; i < logo->clutsize; i += n) {
  		n = logo->clutsize - i;
  		/* palette_cmap provides space for only 16 colors at once */
  		if (n > 16)
  			n = 16;
  		palette_cmap.start = 32 + i;
  		palette_cmap.len = n;
  		for (j = 0; j < n; ++j) {
  			palette_cmap.red[j] = clut[0] << 8 | clut[0];
  			palette_cmap.green[j] = clut[1] << 8 | clut[1];
  			palette_cmap.blue[j] = clut[2] << 8 | clut[2];
  			clut += 3;
  		}
  		fb_set_cmap(&palette_cmap, info);
  	}
  }
  
  static void  fb_set_logo_truepalette(struct fb_info *info,
  					    const struct linux_logo *logo,
  					    u32 *palette)
  {
0128beeee   Helge Deller   [PATCH] constify ...
225
  	static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  	unsigned char redmask, greenmask, bluemask;
  	int redshift, greenshift, blueshift;
  	int i;
  	const unsigned char *clut = logo->clut;
  
  	/*
  	 * We have to create a temporary palette since console palette is only
  	 * 16 colors long.
  	 */
  	/* Bug: Doesn't obey msb_right ... (who needs that?) */
  	redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];
  	greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
  	bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];
  	redshift   = info->var.red.offset   - (8 - info->var.red.length);
  	greenshift = info->var.green.offset - (8 - info->var.green.length);
  	blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);
  
  	for ( i = 0; i < logo->clutsize; i++) {
  		palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
  				 safe_shift((clut[1] & greenmask), greenshift) |
  				 safe_shift((clut[2] & bluemask), blueshift));
  		clut += 3;
  	}
  }
  
  static void fb_set_logo_directpalette(struct fb_info *info,
  					     const struct linux_logo *logo,
  					     u32 *palette)
  {
  	int redshift, greenshift, blueshift;
  	int i;
  
  	redshift = info->var.red.offset;
  	greenshift = info->var.green.offset;
  	blueshift = info->var.blue.offset;
cf7ee554f   Clemens Ladisch   fbdev: clean the ...
261
  	for (i = 32; i < 32 + logo->clutsize; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
267
268
  		palette[i] = i << redshift | i << greenshift | i << blueshift;
  }
  
  static void fb_set_logo(struct fb_info *info,
  			       const struct linux_logo *logo, u8 *dst,
  			       int depth)
  {
b8c909454   Antonino A. Daplas   [PATCH] fbdev: Fi...
269
  	int i, j, k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  	const u8 *src = logo->data;
b8c909454   Antonino A. Daplas   [PATCH] fbdev: Fi...
271
272
  	u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
  	u8 fg = 1, d;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273

1692b37c9   Antonino A. Daplas   fbdev: Fix logo i...
274
275
276
277
278
279
280
281
  	switch (fb_get_color_depth(&info->var, &info->fix)) {
  	case 1:
  		fg = 1;
  		break;
  	case 2:
  		fg = 3;
  		break;
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  		fg = 7;
1692b37c9   Antonino A. Daplas   fbdev: Fix logo i...
283
284
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285

b8c909454   Antonino A. Daplas   [PATCH] fbdev: Fi...
286
287
288
  	if (info->fix.visual == FB_VISUAL_MONO01 ||
  	    info->fix.visual == FB_VISUAL_MONO10)
  		fg = ~((u8) (0xfff << info->var.green.length));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  	switch (depth) {
  	case 4:
  		for (i = 0; i < logo->height; i++)
  			for (j = 0; j < logo->width; src++) {
  				*dst++ = *src >> 4;
  				j++;
  				if (j < logo->width) {
  					*dst++ = *src & 0x0f;
  					j++;
  				}
  			}
  		break;
  	case 1:
  		for (i = 0; i < logo->height; i++) {
  			for (j = 0; j < logo->width; src++) {
  				d = *src ^ xor;
  				for (k = 7; k >= 0; k--) {
  					*dst++ = ((d >> k) & 1) ? fg : 0;
  					j++;
  				}
  			}
  		}
  		break;
  	}
  }
  
  /*
   * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors),
   * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on
   * the visual format and color depth of the framebuffer, the DAC, the
   * pseudo_palette, and the logo data will be adjusted accordingly.
   *
   * Case 1 - linux_logo_clut224:
   * Color exceeds the number of console colors (16), thus we set the hardware DAC
   * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set.
   *
   * For visuals that require color info from the pseudo_palette, we also construct
   * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
   * will be set.
   *
   * Case 2 - linux_logo_vga16:
   * The number of colors just matches the console colors, thus there is no need
   * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie,
   * each byte contains color information for two pixels (upper and lower nibble).
   * To be consistent with fb_imageblit() usage, we therefore separate the two
   * nibbles into separate bytes. The "depth" flag will be set to 4.
   *
   * Case 3 - linux_logo_mono:
   * This is similar with Case 2.  Each byte contains information for 8 pixels.
   * We isolate each bit and expand each into a byte. The "depth" flag will
   * be set to 1.
   */
  static struct logo_data {
  	int depth;
  	int needs_directpalette;
  	int needs_truepalette;
  	int needs_cmapreset;
  	const struct linux_logo *logo;
0128beeee   Helge Deller   [PATCH] constify ...
347
  } fb_logo __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348

9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
349
350
351
352
353
354
355
356
357
358
359
360
  static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
  {
  	u32 size = width * height, i;
  
  	out += size - 1;
  
  	for (i = size; i--; )
  		*out-- = *in++;
  }
  
  static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
  {
f837e6f73   Antonino A. Daplas   [PATCH] fbdev: Fi...
361
  	int i, j, h = height - 1;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
362
363
364
  
  	for (i = 0; i < height; i++)
  		for (j = 0; j < width; j++)
f837e6f73   Antonino A. Daplas   [PATCH] fbdev: Fi...
365
  				out[height * j + h - i] = *in++;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  }
  
  static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
  {
  	int i, j, w = width - 1;
  
  	for (i = 0; i < height; i++)
  		for (j = 0; j < width; j++)
  			out[height * (w - j) + i] = *in++;
  }
  
  static void fb_rotate_logo(struct fb_info *info, u8 *dst,
  			   struct fb_image *image, int rotate)
  {
  	u32 tmp;
  
  	if (rotate == FB_ROTATE_UD) {
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
383
384
  		fb_rotate_logo_ud(image->data, dst, image->width,
  				  image->height);
abed5d15a   Geert Uytterhoeven   fbdev: correct im...
385
386
  		image->dx = info->var.xres - image->width - image->dx;
  		image->dy = info->var.yres - image->height - image->dy;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
387
  	} else if (rotate == FB_ROTATE_CW) {
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
388
389
  		fb_rotate_logo_cw(image->data, dst, image->width,
  				  image->height);
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
390
391
392
  		tmp = image->width;
  		image->width = image->height;
  		image->height = tmp;
abed5d15a   Geert Uytterhoeven   fbdev: correct im...
393
394
395
  		tmp = image->dy;
  		image->dy = image->dx;
  		image->dx = info->var.xres - image->width - tmp;
f837e6f73   Antonino A. Daplas   [PATCH] fbdev: Fi...
396
  	} else if (rotate == FB_ROTATE_CCW) {
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
397
398
  		fb_rotate_logo_ccw(image->data, dst, image->width,
  				   image->height);
f837e6f73   Antonino A. Daplas   [PATCH] fbdev: Fi...
399
400
401
  		tmp = image->width;
  		image->width = image->height;
  		image->height = tmp;
abed5d15a   Geert Uytterhoeven   fbdev: correct im...
402
403
404
  		tmp = image->dx;
  		image->dx = image->dy;
  		image->dy = info->var.yres - image->height - tmp;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
405
406
407
408
409
410
  	}
  
  	image->data = dst;
  }
  
  static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
411
  			    int rotate, unsigned int num)
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
412
  {
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
413
  	unsigned int x;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
414
415
  
  	if (rotate == FB_ROTATE_UR) {
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
416
417
418
  		for (x = 0;
  		     x < num && image->dx + image->width <= info->var.xres;
  		     x++) {
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
419
  			info->fbops->fb_imageblit(info, image);
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
420
  			image->dx += image->width + 8;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
421
422
  		}
  	} else if (rotate == FB_ROTATE_UD) {
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
423
  		for (x = 0; x < num && image->dx >= 0; x++) {
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
424
  			info->fbops->fb_imageblit(info, image);
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
425
  			image->dx -= image->width + 8;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
426
427
  		}
  	} else if (rotate == FB_ROTATE_CW) {
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
428
429
430
  		for (x = 0;
  		     x < num && image->dy + image->height <= info->var.yres;
  		     x++) {
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
431
  			info->fbops->fb_imageblit(info, image);
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
432
  			image->dy += image->height + 8;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
433
434
  		}
  	} else if (rotate == FB_ROTATE_CCW) {
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
435
  		for (x = 0; x < num && image->dy >= 0; x++) {
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
436
  			info->fbops->fb_imageblit(info, image);
448d47974   Geert Uytterhoeven   fbdev: fb_do_show...
437
  			image->dy -= image->height + 8;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
438
439
440
  		}
  	}
  }
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
441
442
443
  static int fb_show_logo_line(struct fb_info *info, int rotate,
  			     const struct linux_logo *logo, int y,
  			     unsigned int n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  {
  	u32 *palette = NULL, *saved_pseudo_palette = NULL;
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
446
  	unsigned char *logo_new = NULL, *logo_rotate = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  	struct fb_image image;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
  
  	/* Return if the frame buffer is not mapped or suspended */
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
450
  	if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
70802c603   Antonino A. Daplas   fbdev: don't show...
451
  	    info->flags & FBINFO_MODULE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
  		return 0;
  
  	image.depth = 8;
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
455
  	image.data = logo->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
  
  	if (fb_logo.needs_cmapreset)
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
458
  		fb_set_logocmap(info, logo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459

9900abfb5   Geert Uytterhoeven   fbdev: Add fb_app...
460
  	if (fb_logo.needs_truepalette ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
  	    fb_logo.needs_directpalette) {
  		palette = kmalloc(256 * 4, GFP_KERNEL);
  		if (palette == NULL)
  			return 0;
  
  		if (fb_logo.needs_truepalette)
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
467
  			fb_set_logo_truepalette(info, logo, palette);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  		else
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
469
  			fb_set_logo_directpalette(info, logo, palette);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
  
  		saved_pseudo_palette = info->pseudo_palette;
  		info->pseudo_palette = palette;
  	}
  
  	if (fb_logo.depth <= 4) {
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
476
  		logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
  		if (logo_new == NULL) {
  			kfree(palette);
  			if (saved_pseudo_palette)
  				info->pseudo_palette = saved_pseudo_palette;
  			return 0;
  		}
  		image.data = logo_new;
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
484
  		fb_set_logo(info, logo, logo_new, fb_logo.depth);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  	}
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
486
  	image.dx = 0;
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
487
488
489
  	image.dy = y;
  	image.width = logo->width;
  	image.height = logo->height;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490

9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
491
  	if (rotate) {
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
492
493
  		logo_rotate = kmalloc(logo->width *
  				      logo->height, GFP_KERNEL);
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
494
495
  		if (logo_rotate)
  			fb_rotate_logo(info, logo_rotate, &image, rotate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  	}
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
497

90da63e54   Geert Uytterhoeven   fbdev: extract fb...
498
  	fb_do_show_logo(info, &image, rotate, n);
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
499

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
502
503
  	kfree(palette);
  	if (saved_pseudo_palette != NULL)
  		info->pseudo_palette = saved_pseudo_palette;
  	kfree(logo_new);
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
504
  	kfree(logo_rotate);
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
505
506
  	return logo->height;
  }
9900abfb5   Geert Uytterhoeven   fbdev: Add fb_app...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  
  #ifdef CONFIG_FB_LOGO_EXTRA
  
  #define FB_LOGO_EX_NUM_MAX 10
  static struct logo_data_extra {
  	const struct linux_logo *logo;
  	unsigned int n;
  } fb_logo_ex[FB_LOGO_EX_NUM_MAX];
  static unsigned int fb_logo_ex_num;
  
  void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
  {
  	if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
  		return;
  
  	fb_logo_ex[fb_logo_ex_num].logo = logo;
  	fb_logo_ex[fb_logo_ex_num].n = n;
  	fb_logo_ex_num++;
  }
  
  static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
  				  unsigned int yres)
  {
  	unsigned int i;
  
  	/* FIXME: logo_ex supports only truecolor fb. */
  	if (info->fix.visual != FB_VISUAL_TRUECOLOR)
  		fb_logo_ex_num = 0;
  
  	for (i = 0; i < fb_logo_ex_num; i++) {
4fb6de256   Geert Uytterhoeven   fbdev/logo: check...
537
538
539
540
  		if (fb_logo_ex[i].logo->type != fb_logo.logo->type) {
  			fb_logo_ex[i].logo = NULL;
  			continue;
  		}
9900abfb5   Geert Uytterhoeven   fbdev: Add fb_app...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  		height += fb_logo_ex[i].logo->height;
  		if (height > yres) {
  			height -= fb_logo_ex[i].logo->height;
  			fb_logo_ex_num = i;
  			break;
  		}
  	}
  	return height;
  }
  
  static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
  {
  	unsigned int i;
  
  	for (i = 0; i < fb_logo_ex_num; i++)
  		y += fb_show_logo_line(info, rotate,
  				       fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
  
  	return y;
  }
  
  #else /* !CONFIG_FB_LOGO_EXTRA */
  
  static inline int fb_prepare_extra_logos(struct fb_info *info,
  					 unsigned int height,
  					 unsigned int yres)
  {
  	return height;
  }
  
  static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
  {
  	return y;
  }
  
  #endif /* CONFIG_FB_LOGO_EXTRA */
  
  
  int fb_prepare_logo(struct fb_info *info, int rotate)
  {
  	int depth = fb_get_color_depth(&info->var, &info->fix);
  	unsigned int yres;
  
  	memset(&fb_logo, 0, sizeof(struct logo_data));
  
  	if (info->flags & FBINFO_MISC_TILEBLITTING ||
  	    info->flags & FBINFO_MODULE)
  		return 0;
  
  	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
  		depth = info->var.blue.length;
  		if (info->var.red.length < depth)
  			depth = info->var.red.length;
  		if (info->var.green.length < depth)
  			depth = info->var.green.length;
  	}
  
  	if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
  		/* assume console colormap */
  		depth = 4;
  	}
9900abfb5   Geert Uytterhoeven   fbdev: Add fb_app...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
  	/* Return if no suitable logo was found */
  	fb_logo.logo = fb_find_logo(depth);
  
  	if (!fb_logo.logo) {
  		return 0;
  	}
  
  	if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
  		yres = info->var.yres;
  	else
  		yres = info->var.xres;
  
  	if (fb_logo.logo->height > yres) {
  		fb_logo.logo = NULL;
  		return 0;
  	}
  
  	/* What depth we asked for might be different from what we get */
  	if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
  		fb_logo.depth = 8;
  	else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
  		fb_logo.depth = 4;
  	else
  		fb_logo.depth = 1;
1692b37c9   Antonino A. Daplas   fbdev: Fix logo i...
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
  
   	if (fb_logo.depth > 4 && depth > 4) {
   		switch (info->fix.visual) {
   		case FB_VISUAL_TRUECOLOR:
   			fb_logo.needs_truepalette = 1;
   			break;
   		case FB_VISUAL_DIRECTCOLOR:
   			fb_logo.needs_directpalette = 1;
   			fb_logo.needs_cmapreset = 1;
   			break;
   		case FB_VISUAL_PSEUDOCOLOR:
   			fb_logo.needs_cmapreset = 1;
   			break;
   		}
   	}
9900abfb5   Geert Uytterhoeven   fbdev: Add fb_app...
641
642
  	return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
  }
90da63e54   Geert Uytterhoeven   fbdev: extract fb...
643
644
  int fb_show_logo(struct fb_info *info, int rotate)
  {
9900abfb5   Geert Uytterhoeven   fbdev: Add fb_app...
645
646
647
648
649
650
651
  	int y;
  
  	y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
  			      num_online_cpus());
  	y = fb_show_extra_logos(info, y, rotate);
  
  	return y;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
  }
  #else
9c44e5f6c   Antonino A. Daplas   [PATCH] fbcon: Co...
654
655
  int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
  int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  #endif /* CONFIG_LOGO */
0aa163418   Alexey Dobriyan   fb: convert /proc...
657
658
  static void *fb_seq_start(struct seq_file *m, loff_t *pos)
  {
698b36827   Linus Torvalds   fbcon: add lifeti...
659
  	mutex_lock(&registration_lock);
0aa163418   Alexey Dobriyan   fb: convert /proc...
660
661
662
663
664
665
666
667
668
669
  	return (*pos < FB_MAX) ? pos : NULL;
  }
  
  static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos)
  {
  	(*pos)++;
  	return (*pos < FB_MAX) ? pos : NULL;
  }
  
  static void fb_seq_stop(struct seq_file *m, void *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  {
698b36827   Linus Torvalds   fbcon: add lifeti...
671
  	mutex_unlock(&registration_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  }
0aa163418   Alexey Dobriyan   fb: convert /proc...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
  static int fb_seq_show(struct seq_file *m, void *v)
  {
  	int i = *(loff_t *)v;
  	struct fb_info *fi = registered_fb[i];
  
  	if (fi)
  		seq_printf(m, "%d %s
  ", fi->node, fi->fix.id);
  	return 0;
  }
  
  static const struct seq_operations proc_fb_seq_ops = {
  	.start	= fb_seq_start,
  	.next	= fb_seq_next,
  	.stop	= fb_seq_stop,
  	.show	= fb_seq_show,
  };
  
  static int proc_fb_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &proc_fb_seq_ops);
  }
  
  static const struct file_operations fb_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= proc_fb_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= seq_release,
  };
c47747fde   Linus Torvalds   fbmem: make read/...
703
704
705
706
707
708
709
710
711
  /*
   * We hold a reference to the fb_info in file->private_data,
   * but if the current registered fb has changed, we don't
   * actually want to use it.
   *
   * So look up the fb_info using the inode minor number,
   * and just verify it against the reference we have.
   */
  static struct fb_info *file_fb_info(struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  {
ad9a824e0   Josef Sipek   [PATCH] struct pa...
713
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
  	int fbidx = iminor(inode);
  	struct fb_info *info = registered_fb[fbidx];
c47747fde   Linus Torvalds   fbmem: make read/...
716
717
718
719
720
721
722
723
724
725
726
  
  	if (info != file->private_data)
  		info = NULL;
  	return info;
  }
  
  static ssize_t
  fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  {
  	unsigned long p = *ppos;
  	struct fb_info *info = file_fb_info(file);
f11b478d4   James Hogan   fbmem: fix fb_rea...
727
728
729
  	u8 *buffer, *dst;
  	u8 __iomem *src;
  	int c, cnt = 0, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
732
733
734
735
736
737
738
  	unsigned long total_size;
  
  	if (!info || ! info->screen_base)
  		return -ENODEV;
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return -EPERM;
  
  	if (info->fbops->fb_read)
3f9b0880e   Antonino A. Daplas   fbdev: pass struc...
739
  		return info->fbops->fb_read(info, buf, count, ppos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  	
  	total_size = info->screen_size;
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
742

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
  	if (total_size == 0)
  		total_size = info->fix.smem_len;
  
  	if (p >= total_size)
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
747
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	if (count >= total_size)
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
749
  		count = total_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  	if (count + p > total_size)
  		count = total_size - p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
  	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
  			 GFP_KERNEL);
  	if (!buffer)
  		return -ENOMEM;
f11b478d4   James Hogan   fbmem: fix fb_rea...
756
  	src = (u8 __iomem *) (info->screen_base + p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
762
763
  
  	if (info->fbops->fb_sync)
  		info->fbops->fb_sync(info);
  
  	while (count) {
  		c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  		dst = buffer;
f11b478d4   James Hogan   fbmem: fix fb_rea...
764
765
766
  		fb_memcpy_fromfb(dst, src, c);
  		dst += c;
  		src += c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
774
775
776
777
778
  
  		if (copy_to_user(buf, buffer, c)) {
  			err = -EFAULT;
  			break;
  		}
  		*ppos += c;
  		buf += c;
  		cnt += c;
  		count -= c;
  	}
  
  	kfree(buffer);
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
779

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
783
784
785
786
  	return (err) ? err : cnt;
  }
  
  static ssize_t
  fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  {
  	unsigned long p = *ppos;
c47747fde   Linus Torvalds   fbmem: make read/...
787
  	struct fb_info *info = file_fb_info(file);
f11b478d4   James Hogan   fbmem: fix fb_rea...
788
789
790
  	u8 *buffer, *src;
  	u8 __iomem *dst;
  	int c, cnt = 0, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
794
795
796
797
798
799
  	unsigned long total_size;
  
  	if (!info || !info->screen_base)
  		return -ENODEV;
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return -EPERM;
  
  	if (info->fbops->fb_write)
3f9b0880e   Antonino A. Daplas   fbdev: pass struc...
800
  		return info->fbops->fb_write(info, buf, count, ppos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
  	
  	total_size = info->screen_size;
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
803

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
  	if (total_size == 0)
  		total_size = info->fix.smem_len;
  
  	if (p > total_size)
6a2a88668   Antonino A. Daplas   [PATCH] fbdev: Fi...
808
  		return -EFBIG;
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
809

6a2a88668   Antonino A. Daplas   [PATCH] fbdev: Fi...
810
811
  	if (count > total_size) {
  		err = -EFBIG;
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
812
  		count = total_size;
6a2a88668   Antonino A. Daplas   [PATCH] fbdev: Fi...
813
814
815
816
817
  	}
  
  	if (count + p > total_size) {
  		if (!err)
  			err = -ENOSPC;
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
818

0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
819
  		count = total_size - p;
6a2a88668   Antonino A. Daplas   [PATCH] fbdev: Fi...
820
  	}
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
821

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
824
825
  	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
  			 GFP_KERNEL);
  	if (!buffer)
  		return -ENOMEM;
f11b478d4   James Hogan   fbmem: fix fb_rea...
826
  	dst = (u8 __iomem *) (info->screen_base + p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
830
831
832
833
  
  	if (info->fbops->fb_sync)
  		info->fbops->fb_sync(info);
  
  	while (count) {
  		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  		src = buffer;
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
834

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
  		if (copy_from_user(src, buf, c)) {
  			err = -EFAULT;
  			break;
  		}
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
839

f11b478d4   James Hogan   fbmem: fix fb_rea...
840
841
842
  		fb_memcpy_tofb(dst, src, c);
  		dst += c;
  		src += c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
  		*ppos += c;
  		buf += c;
  		cnt += c;
  		count -= c;
  	}
0a484a3af   Antonino A. Daplas   [PATCH] fbdev: Fi...
848

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  	kfree(buffer);
6a2a88668   Antonino A. Daplas   [PATCH] fbdev: Fi...
850
  	return (cnt) ? cnt : err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
  int
  fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
  {
1207069f6   Antonino A. Daplas   [PATCH] fbdev: Pa...
855
  	struct fb_fix_screeninfo *fix = &info->fix;
7572a1ea0   Ville Syrjala   fbdev: xoffset, y...
856
857
  	unsigned int yres = info->var.yres;
  	int err = 0;
1207069f6   Antonino A. Daplas   [PATCH] fbdev: Pa...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
  
  	if (var->yoffset > 0) {
  		if (var->vmode & FB_VMODE_YWRAP) {
  			if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
  				err = -EINVAL;
  			else
  				yres = 0;
  		} else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
  			err = -EINVAL;
  	}
  
  	if (var->xoffset > 0 && (!fix->xpanstep ||
  				 (var->xoffset % fix->xpanstep)))
  		err = -EINVAL;
7572a1ea0   Ville Syrjala   fbdev: xoffset, y...
872
  	if (err || !info->fbops->fb_pan_display ||
99e9e7d62   Florian Tobias Schandinat   fb: fix fb_pan_di...
873
874
  	    var->yoffset > info->var.yres_virtual - yres ||
  	    var->xoffset > info->var.xres_virtual - info->var.xres)
1207069f6   Antonino A. Daplas   [PATCH] fbdev: Pa...
875
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
  	if ((err = info->fbops->fb_pan_display(var, info)))
  		return err;
c9c62dce3   James Hogan   fbmem: fix whites...
879
880
881
882
883
884
885
  	info->var.xoffset = var->xoffset;
  	info->var.yoffset = var->yoffset;
  	if (var->vmode & FB_VMODE_YWRAP)
  		info->var.vmode |= FB_VMODE_YWRAP;
  	else
  		info->var.vmode &= ~FB_VMODE_YWRAP;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  }
38a3dc518   Antonino A. Daplas   fbdev: fbcon: che...
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
  static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
  			 u32 activate)
  {
  	struct fb_event event;
  	struct fb_blit_caps caps, fbcaps;
  	int err = 0;
  
  	memset(&caps, 0, sizeof(caps));
  	memset(&fbcaps, 0, sizeof(fbcaps));
  	caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
  	event.info = info;
  	event.data = &caps;
  	fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
  	info->fbops->fb_get_caps(info, &fbcaps, var);
  
  	if (((fbcaps.x ^ caps.x) & caps.x) ||
  	    ((fbcaps.y ^ caps.y) & caps.y) ||
  	    (fbcaps.len < caps.len))
  		err = -EINVAL;
  
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
  int
  fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
  {
b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
912
913
  	int flags = info->flags;
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
  
  	if (var->activate & FB_ACTIVATE_INV_MODE) {
  		struct fb_videomode mode1, mode2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
924
925
926
927
  
  		fb_var_to_videomode(&mode1, var);
  		fb_var_to_videomode(&mode2, &info->var);
  		/* make sure we don't delete the videomode of current var */
  		ret = fb_mode_is_equal(&mode1, &mode2);
  
  		if (!ret) {
  		    struct fb_event event;
  
  		    event.info = info;
  		    event.data = &mode1;
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
928
  		    ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
932
  		}
  
  		if (!ret)
  		    fb_delete_videomode(&mode1, &info->modelist);
b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
933
934
935
  
  		ret = (ret) ? -EINVAL : 0;
  		goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
939
  	}
  
  	if ((var->activate & FB_ACTIVATE_FORCE) ||
  	    memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
4941cb7a1   Antonino A. Daplas   fbdev: save the a...
940
  		u32 activate = var->activate;
fb21c2f42   Laurent Pinchart   fbdev: Add FOURCC...
941
942
943
944
945
946
947
948
949
950
951
952
953
  		/* When using FOURCC mode, make sure the red, green, blue and
  		 * transp fields are set to 0.
  		 */
  		if ((info->fix.capabilities & FB_CAP_FOURCC) &&
  		    var->grayscale > 1) {
  			if (var->red.offset     || var->green.offset    ||
  			    var->blue.offset    || var->transp.offset   ||
  			    var->red.length     || var->green.length    ||
  			    var->blue.length    || var->transp.length   ||
  			    var->red.msb_right  || var->green.msb_right ||
  			    var->blue.msb_right || var->transp.msb_right)
  				return -EINVAL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
  		if (!info->fbops->fb_check_var) {
  			*var = info->var;
b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
956
  			goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  		}
b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
958
959
960
961
  		ret = info->fbops->fb_check_var(var, info);
  
  		if (ret)
  			goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
  
  		if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
0fcf6ada2   Florian Tobias Schandinat   fb: do not ignore...
964
  			struct fb_var_screeninfo old_var;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  			struct fb_videomode mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966

38a3dc518   Antonino A. Daplas   fbdev: fbcon: che...
967
  			if (info->fbops->fb_get_caps) {
b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
968
  				ret = fb_check_caps(info, var, activate);
38a3dc518   Antonino A. Daplas   fbdev: fbcon: che...
969

b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
970
  				if (ret)
38a3dc518   Antonino A. Daplas   fbdev: fbcon: che...
971
972
  					goto done;
  			}
0fcf6ada2   Florian Tobias Schandinat   fb: do not ignore...
973
  			old_var = info->var;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  			info->var = *var;
38a3dc518   Antonino A. Daplas   fbdev: fbcon: che...
975

0fcf6ada2   Florian Tobias Schandinat   fb: do not ignore...
976
977
978
979
980
981
982
983
984
985
986
987
  			if (info->fbops->fb_set_par) {
  				ret = info->fbops->fb_set_par(info);
  
  				if (ret) {
  					info->var = old_var;
  					printk(KERN_WARNING "detected "
  						"fb_set_par error, "
  						"error code: %d
  ", ret);
  					goto done;
  				}
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
  
  			fb_pan_display(info, &info->var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  			fb_set_cmap(&info->cmap, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
994
  			fb_var_to_videomode(&mode, &info->var);
  
  			if (info->modelist.prev && info->modelist.next &&
  			    !list_empty(&info->modelist))
b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
995
  				ret = fb_add_videomode(&mode, &info->modelist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996

b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
997
  			if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
  				struct fb_event event;
4941cb7a1   Antonino A. Daplas   fbdev: save the a...
999
  				int evnt = (activate & FB_ACTIVATE_ALL) ?
7726e9e10   Antonino A. Daplas   [PATCH] fbdev: Ad...
1000
1001
  					FB_EVENT_MODE_CHANGE_ALL :
  					FB_EVENT_MODE_CHANGE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
  
  				info->flags &= ~FBINFO_MISC_USEREVENT;
  				event.info = info;
faa312da9   Eric Miao   lcd: allow lcd de...
1005
  				event.data = &mode;
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
1006
  				fb_notifier_call_chain(evnt, &event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
  			}
  		}
  	}
38a3dc518   Antonino A. Daplas   fbdev: fbcon: che...
1010
1011
  
   done:
b1e7223f2   Antonino A. Daplas   fbdev: clean up e...
1012
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
  }
  
  int
  fb_blank(struct fb_info *info, int blank)
  {	
   	int ret = -EINVAL;
  
   	if (blank > FB_BLANK_POWERDOWN)
   		blank = FB_BLANK_POWERDOWN;
  
  	if (info->fbops->fb_blank)
   		ret = info->fbops->fb_blank(blank, info);
  
   	if (!ret) {
  		struct fb_event event;
  
  		event.info = info;
  		event.data = &blank;
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
1031
  		fb_notifier_call_chain(FB_EVENT_BLANK, &event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
1034
1035
  	}
  
   	return ret;
  }
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1036
1037
  static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
  			unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
  {
e53677113   Alan Cox   fb: push down the...
1039
  	struct fb_ops *fb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
1042
  	struct fb_var_screeninfo var;
  	struct fb_fix_screeninfo fix;
  	struct fb_con2fbmap con2fb;
1f5e31d7e   Andrea Righi   fbmem: don't call...
1043
  	struct fb_cmap cmap_from;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
  	struct fb_cmap_user cmap;
  	struct fb_event event;
  	void __user *argp = (void __user *)arg;
e53677113   Alan Cox   fb: push down the...
1047
  	long ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
  	switch (cmd) {
  	case FBIOGET_VSCREENINFO:
1f5e31d7e   Andrea Righi   fbmem: don't call...
1050
1051
1052
1053
1054
1055
  		if (!lock_fb_info(info))
  			return -ENODEV;
  		var = info->var;
  		unlock_fb_info(info);
  
  		ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
e53677113   Alan Cox   fb: push down the...
1056
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
  	case FBIOPUT_VSCREENINFO:
1f5e31d7e   Andrea Righi   fbmem: don't call...
1058
1059
1060
1061
  		if (copy_from_user(&var, argp, sizeof(var)))
  			return -EFAULT;
  		if (!lock_fb_info(info))
  			return -ENODEV;
ac751efa6   Torben Hohn   console: rename a...
1062
  		console_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
  		info->flags |= FBINFO_MISC_USEREVENT;
e53677113   Alan Cox   fb: push down the...
1064
  		ret = fb_set_var(info, &var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
  		info->flags &= ~FBINFO_MISC_USEREVENT;
ac751efa6   Torben Hohn   console: rename a...
1066
  		console_unlock();
1f5e31d7e   Andrea Righi   fbmem: don't call...
1067
1068
  		unlock_fb_info(info);
  		if (!ret && copy_to_user(argp, &var, sizeof(var)))
e53677113   Alan Cox   fb: push down the...
1069
1070
  			ret = -EFAULT;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
  	case FBIOGET_FSCREENINFO:
1f5e31d7e   Andrea Righi   fbmem: don't call...
1072
1073
1074
1075
1076
1077
  		if (!lock_fb_info(info))
  			return -ENODEV;
  		fix = info->fix;
  		unlock_fb_info(info);
  
  		ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
e53677113   Alan Cox   fb: push down the...
1078
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
  	case FBIOPUTCMAP:
  		if (copy_from_user(&cmap, argp, sizeof(cmap)))
1f5e31d7e   Andrea Righi   fbmem: don't call...
1081
1082
  			return -EFAULT;
  		ret = fb_set_user_cmap(&cmap, info);
e53677113   Alan Cox   fb: push down the...
1083
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
  	case FBIOGETCMAP:
  		if (copy_from_user(&cmap, argp, sizeof(cmap)))
1f5e31d7e   Andrea Righi   fbmem: don't call...
1086
1087
1088
1089
1090
1091
  			return -EFAULT;
  		if (!lock_fb_info(info))
  			return -ENODEV;
  		cmap_from = info->cmap;
  		unlock_fb_info(info);
  		ret = fb_cmap_to_user(&cmap_from, &cmap);
e53677113   Alan Cox   fb: push down the...
1092
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  	case FBIOPAN_DISPLAY:
1f5e31d7e   Andrea Righi   fbmem: don't call...
1094
1095
1096
1097
  		if (copy_from_user(&var, argp, sizeof(var)))
  			return -EFAULT;
  		if (!lock_fb_info(info))
  			return -ENODEV;
ac751efa6   Torben Hohn   console: rename a...
1098
  		console_lock();
e53677113   Alan Cox   fb: push down the...
1099
  		ret = fb_pan_display(info, &var);
ac751efa6   Torben Hohn   console: rename a...
1100
  		console_unlock();
1f5e31d7e   Andrea Righi   fbmem: don't call...
1101
  		unlock_fb_info(info);
e53677113   Alan Cox   fb: push down the...
1102
  		if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
1f5e31d7e   Andrea Righi   fbmem: don't call...
1103
  			return -EFAULT;
e53677113   Alan Cox   fb: push down the...
1104
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
  	case FBIO_CURSOR:
e53677113   Alan Cox   fb: push down the...
1106
1107
  		ret = -EINVAL;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
  	case FBIOGET_CON2FBMAP:
  		if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
1f5e31d7e   Andrea Righi   fbmem: don't call...
1110
1111
1112
1113
1114
  			return -EFAULT;
  		if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
  			return -EINVAL;
  		con2fb.framebuffer = -1;
  		event.data = &con2fb;
513adb586   Andrea Righi   fbdev: fix info->...
1115
1116
  		if (!lock_fb_info(info))
  			return -ENODEV;
1f5e31d7e   Andrea Righi   fbmem: don't call...
1117
1118
  		event.info = info;
  		fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
513adb586   Andrea Righi   fbdev: fix info->...
1119
  		unlock_fb_info(info);
1f5e31d7e   Andrea Righi   fbmem: don't call...
1120
  		ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
e53677113   Alan Cox   fb: push down the...
1121
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
  	case FBIOPUT_CON2FBMAP:
1f5e31d7e   Andrea Righi   fbmem: don't call...
1123
1124
1125
1126
1127
1128
  		if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
  			return -EFAULT;
  		if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
  			return -EINVAL;
  		if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  		if (!registered_fb[con2fb.framebuffer])
e53677113   Alan Cox   fb: push down the...
1130
1131
1132
1133
1134
  			request_module("fb%d", con2fb.framebuffer);
  		if (!registered_fb[con2fb.framebuffer]) {
  			ret = -EINVAL;
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
  		event.data = &con2fb;
513adb586   Andrea Righi   fbdev: fix info->...
1136
1137
  		if (!lock_fb_info(info))
  			return -ENODEV;
1f5e31d7e   Andrea Righi   fbmem: don't call...
1138
  		event.info = info;
66c1ca019   Andrea Righi   fbmem: fix fb_inf...
1139
  		ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
513adb586   Andrea Righi   fbdev: fix info->...
1140
  		unlock_fb_info(info);
e53677113   Alan Cox   fb: push down the...
1141
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  	case FBIOBLANK:
1f5e31d7e   Andrea Righi   fbmem: don't call...
1143
1144
  		if (!lock_fb_info(info))
  			return -ENODEV;
ac751efa6   Torben Hohn   console: rename a...
1145
  		console_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
  		info->flags |= FBINFO_MISC_USEREVENT;
e53677113   Alan Cox   fb: push down the...
1147
  		ret = fb_blank(info, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
  		info->flags &= ~FBINFO_MISC_USEREVENT;
ac751efa6   Torben Hohn   console: rename a...
1149
  		console_unlock();
1f5e31d7e   Andrea Righi   fbmem: don't call...
1150
1151
  		unlock_fb_info(info);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
  	default:
1f5e31d7e   Andrea Righi   fbmem: don't call...
1153
1154
1155
1156
  		if (!lock_fb_info(info))
  			return -ENODEV;
  		fb = info->fbops;
  		if (fb->fb_ioctl)
e53677113   Alan Cox   fb: push down the...
1157
  			ret = fb->fb_ioctl(info, cmd, arg);
1f5e31d7e   Andrea Righi   fbmem: don't call...
1158
1159
1160
  		else
  			ret = -ENOTTY;
  		unlock_fb_info(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
  	}
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1162
1163
1164
1165
  	return ret;
  }
  
  static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1166
  {
c47747fde   Linus Torvalds   fbmem: make read/...
1167
  	struct fb_info *info = file_fb_info(file);
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1168

c47747fde   Linus Torvalds   fbmem: make read/...
1169
1170
  	if (!info)
  		return -ENODEV;
1f5e31d7e   Andrea Righi   fbmem: don't call...
1171
  	return do_fb_ioctl(info, cmd, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
  }
  
  #ifdef CONFIG_COMPAT
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
  struct fb_fix_screeninfo32 {
  	char			id[16];
  	compat_caddr_t		smem_start;
  	u32			smem_len;
  	u32			type;
  	u32			type_aux;
  	u32			visual;
  	u16			xpanstep;
  	u16			ypanstep;
  	u16			ywrapstep;
  	u32			line_length;
  	compat_caddr_t		mmio_start;
  	u32			mmio_len;
  	u32			accel;
  	u16			reserved[3];
  };
  
  struct fb_cmap32 {
  	u32			start;
  	u32			len;
  	compat_caddr_t	red;
  	compat_caddr_t	green;
  	compat_caddr_t	blue;
  	compat_caddr_t	transp;
  };
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1200
1201
  static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
  			  unsigned long arg)
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
  {
  	struct fb_cmap_user __user *cmap;
  	struct fb_cmap32 __user *cmap32;
  	__u32 data;
  	int err;
  
  	cmap = compat_alloc_user_space(sizeof(*cmap));
  	cmap32 = compat_ptr(arg);
  
  	if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
  		return -EFAULT;
  
  	if (get_user(data, &cmap32->red) ||
  	    put_user(compat_ptr(data), &cmap->red) ||
  	    get_user(data, &cmap32->green) ||
  	    put_user(compat_ptr(data), &cmap->green) ||
  	    get_user(data, &cmap32->blue) ||
  	    put_user(compat_ptr(data), &cmap->blue) ||
  	    get_user(data, &cmap32->transp) ||
  	    put_user(compat_ptr(data), &cmap->transp))
  		return -EFAULT;
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1223
  	err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
  
  	if (!err) {
  		if (copy_in_user(&cmap32->start,
  				 &cmap->start,
  				 2 * sizeof(__u32)))
  			err = -EFAULT;
  	}
  	return err;
  }
  
  static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
  				  struct fb_fix_screeninfo32 __user *fix32)
  {
  	__u32 data;
  	int err;
  
  	err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
  
  	data = (__u32) (unsigned long) fix->smem_start;
  	err |= put_user(data, &fix32->smem_start);
  
  	err |= put_user(fix->smem_len, &fix32->smem_len);
  	err |= put_user(fix->type, &fix32->type);
  	err |= put_user(fix->type_aux, &fix32->type_aux);
  	err |= put_user(fix->visual, &fix32->visual);
  	err |= put_user(fix->xpanstep, &fix32->xpanstep);
  	err |= put_user(fix->ypanstep, &fix32->ypanstep);
  	err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
  	err |= put_user(fix->line_length, &fix32->line_length);
  
  	data = (__u32) (unsigned long) fix->mmio_start;
  	err |= put_user(data, &fix32->mmio_start);
  
  	err |= put_user(fix->mmio_len, &fix32->mmio_len);
  	err |= put_user(fix->accel, &fix32->accel);
  	err |= copy_to_user(fix32->reserved, fix->reserved,
  			    sizeof(fix->reserved));
  
  	return err;
  }
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1264
1265
  static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
  			      unsigned long arg)
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
  {
  	mm_segment_t old_fs;
  	struct fb_fix_screeninfo fix;
  	struct fb_fix_screeninfo32 __user *fix32;
  	int err;
  
  	fix32 = compat_ptr(arg);
  
  	old_fs = get_fs();
  	set_fs(KERNEL_DS);
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1276
  	err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1277
1278
1279
1280
1281
1282
1283
  	set_fs(old_fs);
  
  	if (!err)
  		err = do_fscreeninfo_to_user(&fix, fix32);
  
  	return err;
  }
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1284
1285
  static long fb_compat_ioctl(struct file *file, unsigned int cmd,
  			    unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286
  {
c47747fde   Linus Torvalds   fbmem: make read/...
1287
1288
  	struct fb_info *info = file_fb_info(file);
  	struct fb_ops *fb;
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1289
  	long ret = -ENOIOCTLCMD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290

c47747fde   Linus Torvalds   fbmem: make read/...
1291
1292
1293
  	if (!info)
  		return -ENODEV;
  	fb = info->fbops;
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1294
1295
1296
1297
1298
1299
1300
1301
  	switch(cmd) {
  	case FBIOGET_VSCREENINFO:
  	case FBIOPUT_VSCREENINFO:
  	case FBIOPAN_DISPLAY:
  	case FBIOGET_CON2FBMAP:
  	case FBIOPUT_CON2FBMAP:
  		arg = (unsigned long) compat_ptr(arg);
  	case FBIOBLANK:
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1302
1303
  		ret = do_fb_ioctl(info, cmd, arg);
  		break;
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1304
1305
  
  	case FBIOGET_FSCREENINFO:
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1306
  		ret = fb_get_fscreeninfo(info, cmd, arg);
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1307
1308
1309
1310
  		break;
  
  	case FBIOGETCMAP:
  	case FBIOPUTCMAP:
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1311
  		ret = fb_getput_cmap(info, cmd, arg);
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1312
1313
1314
1315
  		break;
  
  	default:
  		if (fb->fb_compat_ioctl)
67a6680d6   Christoph Hellwig   [PATCH] fbdev: Sa...
1316
  			ret = fb->fb_compat_ioctl(info, cmd, arg);
c7f82d9c4   Arnd Bergmann   [PATCH] fbdev: mo...
1317
1318
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
  	return ret;
  }
  #endif
10eb2659c   Antonino A. Daplas   fbdev: move arch-...
1322
  static int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
  fb_mmap(struct file *file, struct vm_area_struct * vma)
  {
c47747fde   Linus Torvalds   fbmem: make read/...
1325
1326
  	struct fb_info *info = file_fb_info(file);
  	struct fb_ops *fb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
  	unsigned long off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
  	unsigned long start;
  	u32 len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330

c47747fde   Linus Torvalds   fbmem: make read/...
1331
1332
  	if (!info)
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
1334
1335
  	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
  		return -EINVAL;
  	off = vma->vm_pgoff << PAGE_SHIFT;
c47747fde   Linus Torvalds   fbmem: make read/...
1336
  	fb = info->fbops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
1338
  	if (!fb)
  		return -ENODEV;
537a1bf05   Krzysztof Helt   fbdev: add mutex ...
1339
  	mutex_lock(&info->mm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1340
1341
  	if (fb->fb_mmap) {
  		int res;
216d526c8   Christoph Hellwig   [PATCH] fbdev: Sa...
1342
  		res = fb->fb_mmap(info, vma);
537a1bf05   Krzysztof Helt   fbdev: add mutex ...
1343
  		mutex_unlock(&info->mm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344
1345
  		return res;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
1347
1348
1349
1350
1351
1352
  	/* frame buffer memory */
  	start = info->fix.smem_start;
  	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
  	if (off >= len) {
  		/* memory mapped io */
  		off -= len;
  		if (info->var.accel_flags) {
537a1bf05   Krzysztof Helt   fbdev: add mutex ...
1353
  			mutex_unlock(&info->mm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
1355
1356
1357
1358
  			return -EINVAL;
  		}
  		start = info->fix.mmio_start;
  		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
  	}
537a1bf05   Krzysztof Helt   fbdev: add mutex ...
1359
  	mutex_unlock(&info->mm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360
1361
1362
1363
1364
1365
1366
  	start &= PAGE_MASK;
  	if ((vma->vm_end - vma->vm_start + off) > len)
  		return -EINVAL;
  	off += start;
  	vma->vm_pgoff = off >> PAGE_SHIFT;
  	/* This is an IO map - tell maydump to skip this VMA */
  	vma->vm_flags |= VM_IO | VM_RESERVED;
c07fbfd17   Daniel De Graaf   fbmem: VM_IO set,...
1367
  	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
10eb2659c   Antonino A. Daplas   fbdev: move arch-...
1368
  	fb_pgprotect(file, vma, off);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
1370
1371
  	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
  			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
1374
1375
1376
  }
  
  static int
  fb_open(struct inode *inode, struct file *file)
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1377
1378
  __acquires(&info->lock)
  __releases(&info->lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379
1380
1381
1382
  {
  	int fbidx = iminor(inode);
  	struct fb_info *info;
  	int res = 0;
698b36827   Linus Torvalds   fbcon: add lifeti...
1383
1384
  	info = get_fb_info(fbidx);
  	if (!info) {
a65e5d782   Johannes Berg   remove CONFIG_KMO...
1385
  		request_module("fb%d", fbidx);
698b36827   Linus Torvalds   fbcon: add lifeti...
1386
1387
1388
1389
1390
1391
  		info = get_fb_info(fbidx);
  		if (!info)
  			return -ENODEV;
  	}
  	if (IS_ERR(info))
  		return PTR_ERR(info);
3e680aae4   Krzysztof Helt   fb: convert lock/...
1392
  	mutex_lock(&info->lock);
fc7f687a6   Jonathan Corbet   fbmem: cdev lock_...
1393
1394
1395
1396
  	if (!try_module_get(info->fbops->owner)) {
  		res = -ENODEV;
  		goto out;
  	}
cae8a12f4   Thomas Koeller   [PATCH] non-linea...
1397
  	file->private_data = info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
1399
1400
1401
1402
  	if (info->fbops->fb_open) {
  		res = info->fbops->fb_open(info,1);
  		if (res)
  			module_put(info->fbops->owner);
  	}
d847471d0   Ian Campbell   fbdefio: add set_...
1403
1404
1405
1406
  #ifdef CONFIG_FB_DEFERRED_IO
  	if (info->fbdefio)
  		fb_deferred_io_open(info, inode, file);
  #endif
fc7f687a6   Jonathan Corbet   fbmem: cdev lock_...
1407
  out:
3e680aae4   Krzysztof Helt   fb: convert lock/...
1408
  	mutex_unlock(&info->lock);
698b36827   Linus Torvalds   fbcon: add lifeti...
1409
1410
  	if (res)
  		put_fb_info(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411
1412
1413
1414
1415
  	return res;
  }
  
  static int 
  fb_release(struct inode *inode, struct file *file)
a684e7d33   Geert Uytterhoeven   fbdev: fix fb_com...
1416
1417
  __acquires(&info->lock)
  __releases(&info->lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418
  {
cae8a12f4   Thomas Koeller   [PATCH] non-linea...
1419
  	struct fb_info * const info = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1420

3e680aae4   Krzysztof Helt   fb: convert lock/...
1421
  	mutex_lock(&info->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
1424
  	if (info->fbops->fb_release)
  		info->fbops->fb_release(info,1);
  	module_put(info->fbops->owner);
3e680aae4   Krzysztof Helt   fb: convert lock/...
1425
  	mutex_unlock(&info->lock);
698b36827   Linus Torvalds   fbcon: add lifeti...
1426
  	put_fb_info(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
  	return 0;
  }
0128beeee   Helge Deller   [PATCH] constify ...
1429
  static const struct file_operations fb_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1430
1431
1432
  	.owner =	THIS_MODULE,
  	.read =		fb_read,
  	.write =	fb_write,
e53677113   Alan Cox   fb: push down the...
1433
  	.unlocked_ioctl = fb_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
1435
1436
1437
1438
1439
1440
1441
1442
  #ifdef CONFIG_COMPAT
  	.compat_ioctl = fb_compat_ioctl,
  #endif
  	.mmap =		fb_mmap,
  	.open =		fb_open,
  	.release =	fb_release,
  #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
  	.get_unmapped_area = get_fb_unmapped_area,
  #endif
5e841b88d   Paul Mundt   fb: fsync() metho...
1443
1444
1445
  #ifdef CONFIG_FB_DEFERRED_IO
  	.fsync =	fb_deferred_io_fsync,
  #endif
6038f373a   Arnd Bergmann   llseek: automatic...
1446
  	.llseek =	default_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1447
  };
9a1791767   Antonino A. Daplas   [PATCH] Detaching...
1448
1449
  struct class *fb_class;
  EXPORT_SYMBOL(fb_class);
e4c690e06   Anton Vorontsov   fb: add support f...
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
  
  static int fb_check_foreignness(struct fb_info *fi)
  {
  	const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
  
  	fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
  
  #ifdef __BIG_ENDIAN
  	fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
  #else
  	fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
  #endif /* __BIG_ENDIAN */
  
  	if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
  		pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
  		       "support this framebuffer
  ", fi->fix.id);
  		return -ENOSYS;
  	} else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
  		pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
  		       "support this framebuffer
  ", fi->fix.id);
  		return -ENOSYS;
  	}
  
  	return 0;
  }
1471ca9aa   Marcin Slusarz   fbdev: allow pass...
1477
  static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
4410f3910   Dave Airlie   fbdev: add suppor...
1478
1479
  {
  	/* is the generic aperture base the same as the HW one */
1471ca9aa   Marcin Slusarz   fbdev: allow pass...
1480
  	if (gen->base == hw->base)
4410f3910   Dave Airlie   fbdev: add suppor...
1481
1482
  		return true;
  	/* is the generic aperture base inside the hw base->hw base+size */
acd0acb65   Dave Airlie   fb: fix overlappi...
1483
  	if (gen->base > hw->base && gen->base < hw->base + hw->size)
4410f3910   Dave Airlie   fbdev: add suppor...
1484
1485
1486
  		return true;
  	return false;
  }
1471ca9aa   Marcin Slusarz   fbdev: allow pass...
1487

06415c564   Marcin Slusarz   fbmem, drm/nouvea...
1488
1489
  static bool fb_do_apertures_overlap(struct apertures_struct *gena,
  				    struct apertures_struct *hwa)
1471ca9aa   Marcin Slusarz   fbdev: allow pass...
1490
1491
  {
  	int i, j;
1471ca9aa   Marcin Slusarz   fbdev: allow pass...
1492
1493
1494
1495
1496
1497
1498
1499
1500
  	if (!hwa || !gena)
  		return false;
  
  	for (i = 0; i < hwa->count; ++i) {
  		struct aperture *h = &hwa->ranges[i];
  		for (j = 0; j < gena->count; ++j) {
  			struct aperture *g = &gena->ranges[j];
  			printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)
  ",
f4b87dee9   Randy Dunlap   fbmem: avoid prin...
1501
1502
1503
1504
  				(unsigned long long)g->base,
  				(unsigned long long)g->size,
  				(unsigned long long)h->base,
  				(unsigned long long)h->size);
1471ca9aa   Marcin Slusarz   fbdev: allow pass...
1505
1506
1507
1508
1509
1510
1511
  			if (apertures_overlap(g, h))
  				return true;
  		}
  	}
  
  	return false;
  }
712f3147a   Linus Torvalds   fbmem: fix remove...
1512
  static int do_unregister_framebuffer(struct fb_info *fb_info);
3b9676e7a   Marcin Slusarz   vga16fb, drm: vga...
1513
  #define VGA_FB_PHYS 0xA0000
712f3147a   Linus Torvalds   fbmem: fix remove...
1514
  static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
3b9676e7a   Marcin Slusarz   vga16fb, drm: vga...
1515
  				     const char *name, bool primary)
06415c564   Marcin Slusarz   fbmem, drm/nouvea...
1516
1517
1518
1519
1520
  {
  	int i;
  
  	/* check all firmware fbs and kick off if the base addr overlaps */
  	for (i = 0 ; i < FB_MAX; i++) {
3b9676e7a   Marcin Slusarz   vga16fb, drm: vga...
1521
  		struct apertures_struct *gen_aper;
06415c564   Marcin Slusarz   fbmem, drm/nouvea...
1522
1523
1524
1525
1526
  		if (!registered_fb[i])
  			continue;
  
  		if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
  			continue;
3b9676e7a   Marcin Slusarz   vga16fb, drm: vga...
1527
1528
1529
1530
  		gen_aper = registered_fb[i]->apertures;
  		if (fb_do_apertures_overlap(gen_aper, a) ||
  			(primary && gen_aper && gen_aper->count &&
  			 gen_aper->ranges[0].base == VGA_FB_PHYS)) {
47c87d930   Matthew Garrett   fb: Reduce priori...
1531
  			printk(KERN_INFO "fb: conflicting fb hw usage "
06415c564   Marcin Slusarz   fbmem, drm/nouvea...
1532
1533
1534
  			       "%s vs %s - removing generic driver
  ",
  			       name, registered_fb[i]->fix.id);
712f3147a   Linus Torvalds   fbmem: fix remove...
1535
  			do_unregister_framebuffer(registered_fb[i]);
06415c564   Marcin Slusarz   fbmem, drm/nouvea...
1536
1537
1538
  		}
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539

712f3147a   Linus Torvalds   fbmem: fix remove...
1540
  static int do_register_framebuffer(struct fb_info *fb_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1541
1542
1543
  {
  	int i;
  	struct fb_event event;
96fe6a210   Antonino A. Daplas   [PATCH] fbdev: Ad...
1544
  	struct fb_videomode mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545

e4c690e06   Anton Vorontsov   fb: add support f...
1546
1547
  	if (fb_check_foreignness(fb_info))
  		return -ENOSYS;
712f3147a   Linus Torvalds   fbmem: fix remove...
1548
  	do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
3b9676e7a   Marcin Slusarz   vga16fb, drm: vga...
1549
  					 fb_is_primary_device(fb_info));
4410f3910   Dave Airlie   fbdev: add suppor...
1550

c590cece7   Bruno PrĂ©mont   Further fbcon san...
1551
1552
  	if (num_registered_fb == FB_MAX)
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
1554
1555
1556
1557
  	num_registered_fb++;
  	for (i = 0 ; i < FB_MAX; i++)
  		if (!registered_fb[i])
  			break;
  	fb_info->node = i;
698b36827   Linus Torvalds   fbcon: add lifeti...
1558
  	atomic_set(&fb_info->count, 1);
6c96895e9   Linus Torvalds   Revert "fb: Initi...
1559
1560
  	mutex_init(&fb_info->lock);
  	mutex_init(&fb_info->mm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561

77997aaad   Greg Kroah-Hartman   device create: vi...
1562
1563
  	fb_info->dev = device_create(fb_class, fb_info->device,
  				     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
78cde0887   Greg Kroah-Hartman   Driver core: conv...
1564
  	if (IS_ERR(fb_info->dev)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
  		/* Not fatal */
78cde0887   Greg Kroah-Hartman   Driver core: conv...
1566
1567
1568
  		printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld
  ", i, PTR_ERR(fb_info->dev));
  		fb_info->dev = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1569
  	} else
78cde0887   Greg Kroah-Hartman   Driver core: conv...
1570
  		fb_init_device(fb_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
1574
1575
1576
1577
  
  	if (fb_info->pixmap.addr == NULL) {
  		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
  		if (fb_info->pixmap.addr) {
  			fb_info->pixmap.size = FBPIXMAPSIZE;
  			fb_info->pixmap.buf_align = 1;
  			fb_info->pixmap.scan_align = 1;
58a606431   James Simmons   [PATCH] fbdev: fi...
1578
  			fb_info->pixmap.access_align = 32;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579
1580
1581
1582
  			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
  		}
  	}	
  	fb_info->pixmap.offset = 0;
bf26ad72a   Antonino A. Daplas   fbdev: advertise ...
1583
1584
1585
1586
1587
  	if (!fb_info->pixmap.blit_x)
  		fb_info->pixmap.blit_x = ~(u32)0;
  
  	if (!fb_info->pixmap.blit_y)
  		fb_info->pixmap.blit_y = ~(u32)0;
96fe6a210   Antonino A. Daplas   [PATCH] fbdev: Ad...
1588
  	if (!fb_info->modelist.prev || !fb_info->modelist.next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
  		INIT_LIST_HEAD(&fb_info->modelist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1590

96fe6a210   Antonino A. Daplas   [PATCH] fbdev: Ad...
1591
1592
  	fb_var_to_videomode(&mode, &fb_info->var);
  	fb_add_videomode(&mode, &fb_info->modelist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
  	registered_fb[i] = fb_info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594
  	event.info = fb_info;
513adb586   Andrea Righi   fbdev: fix info->...
1595
1596
  	if (!lock_fb_info(fb_info))
  		return -ENODEV;
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
1597
  	fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
513adb586   Andrea Righi   fbdev: fix info->...
1598
  	unlock_fb_info(fb_info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599
1600
  	return 0;
  }
712f3147a   Linus Torvalds   fbmem: fix remove...
1601
  static int do_unregister_framebuffer(struct fb_info *fb_info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
  {
e614b18dc   Antonino A. Daplas   [PATCH] VT bindin...
1603
  	struct fb_event event;
cfafca806   Jesse Barnes   fbdev: fbcon: con...
1604
  	int i, ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
1606
  
  	i = fb_info->node;
c590cece7   Bruno PrĂ©mont   Further fbcon san...
1607
  	if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
712f3147a   Linus Torvalds   fbmem: fix remove...
1608
  		return -EINVAL;
513adb586   Andrea Righi   fbdev: fix info->...
1609
1610
1611
  
  	if (!lock_fb_info(fb_info))
  		return -ENODEV;
cfafca806   Jesse Barnes   fbdev: fbcon: con...
1612
1613
  	event.info = fb_info;
  	ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
513adb586   Andrea Righi   fbdev: fix info->...
1614
  	unlock_fb_info(fb_info);
cfafca806   Jesse Barnes   fbdev: fbcon: con...
1615

712f3147a   Linus Torvalds   fbmem: fix remove...
1616
1617
  	if (ret)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618

e614b18dc   Antonino A. Daplas   [PATCH] VT bindin...
1619
1620
  	if (fb_info->pixmap.addr &&
  	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621
1622
  		kfree(fb_info->pixmap.addr);
  	fb_destroy_modelist(&fb_info->modelist);
698b36827   Linus Torvalds   fbcon: add lifeti...
1623
  	registered_fb[i] = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
  	num_registered_fb--;
78cde0887   Greg Kroah-Hartman   Driver core: conv...
1625
1626
  	fb_cleanup_device(fb_info);
  	device_destroy(fb_class, MKDEV(FB_MAJOR, i));
e614b18dc   Antonino A. Daplas   [PATCH] VT bindin...
1627
  	event.info = fb_info;
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
1628
  	fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
4410f3910   Dave Airlie   fbdev: add suppor...
1629
1630
  
  	/* this may free fb info */
698b36827   Linus Torvalds   fbcon: add lifeti...
1631
  	put_fb_info(fb_info);
712f3147a   Linus Torvalds   fbmem: fix remove...
1632
1633
1634
1635
1636
1637
1638
1639
  	return 0;
  }
  
  void remove_conflicting_framebuffers(struct apertures_struct *a,
  				     const char *name, bool primary)
  {
  	mutex_lock(&registration_lock);
  	do_remove_conflicting_framebuffers(a, name, primary);
698b36827   Linus Torvalds   fbcon: add lifeti...
1640
  	mutex_unlock(&registration_lock);
712f3147a   Linus Torvalds   fbmem: fix remove...
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
  }
  EXPORT_SYMBOL(remove_conflicting_framebuffers);
  
  /**
   *	register_framebuffer - registers a frame buffer device
   *	@fb_info: frame buffer info structure
   *
   *	Registers a frame buffer device @fb_info.
   *
   *	Returns negative errno on error, or zero for success.
   *
   */
  int
  register_framebuffer(struct fb_info *fb_info)
  {
  	int ret;
  
  	mutex_lock(&registration_lock);
  	ret = do_register_framebuffer(fb_info);
  	mutex_unlock(&registration_lock);
  
  	return ret;
  }
  
  /**
   *	unregister_framebuffer - releases a frame buffer device
   *	@fb_info: frame buffer info structure
   *
   *	Unregisters a frame buffer device @fb_info.
   *
   *	Returns negative errno on error, or zero for success.
   *
   *      This function will also notify the framebuffer console
   *      to release the driver.
   *
   *      This is meant to be called within a driver's module_exit()
   *      function. If this is called outside module_exit(), ensure
   *      that the driver implements fb_open() and fb_release() to
   *      check that no processes are using the device.
   */
  int
  unregister_framebuffer(struct fb_info *fb_info)
  {
  	int ret;
  
  	mutex_lock(&registration_lock);
  	ret = do_unregister_framebuffer(fb_info);
  	mutex_unlock(&registration_lock);
cfafca806   Jesse Barnes   fbdev: fbcon: con...
1689
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1690
1691
1692
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
   *	fb_set_suspend - low level driver signals suspend
   *	@info: framebuffer affected
   *	@state: 0 = resuming, !=0 = suspending
   *
   *	This is meant to be used by low level drivers to
   * 	signal suspend/resume to the core & clients.
   *	It must be called with the console semaphore held
   */
  void fb_set_suspend(struct fb_info *info, int state)
  {
  	struct fb_event event;
  
  	event.info = info;
  	if (state) {
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
1707
  		fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
1709
1710
  		info->state = FBINFO_STATE_SUSPENDED;
  	} else {
  		info->state = FBINFO_STATE_RUNNING;
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
1711
  		fb_notifier_call_chain(FB_EVENT_RESUME, &event);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
  	}
  }
  
  /**
   *	fbmem_init - init frame buffer subsystem
   *
   *	Initialize the frame buffer subsystem.
   *
   *	NOTE: This function is _only_ to be called by drivers/char/mem.c.
   *
   */
  
  static int __init
  fbmem_init(void)
  {
0aa163418   Alexey Dobriyan   fb: convert /proc...
1727
  	proc_create("fb", 0, NULL, &fb_proc_fops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1728

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
1730
1731
  	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
  		printk("unable to get major %d for fb devs
  ", FB_MAJOR);
56b229359   Greg Kroah-Hartman   [PATCH] class: co...
1732
  	fb_class = class_create(THIS_MODULE, "graphics");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
  	if (IS_ERR(fb_class)) {
  		printk(KERN_WARNING "Unable to create fb class; errno = %ld
  ", PTR_ERR(fb_class));
  		fb_class = NULL;
  	}
  	return 0;
  }
  
  #ifdef MODULE
  module_init(fbmem_init);
  static void __exit
  fbmem_exit(void)
  {
c43f89c20   Alexey Dobriyan   fbdev: fix /proc/...
1746
  	remove_proc_entry("fb", NULL);
56b229359   Greg Kroah-Hartman   [PATCH] class: co...
1747
  	class_destroy(fb_class);
5a340cce0   Jon Smirl   [PATCH] fbmem: us...
1748
  	unregister_chrdev(FB_MAJOR, "fb");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
  }
  
  module_exit(fbmem_exit);
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Framebuffer base");
  #else
  subsys_initcall(fbmem_init);
  #endif
  
  int fb_new_modelist(struct fb_info *info)
  {
  	struct fb_event event;
  	struct fb_var_screeninfo var = info->var;
  	struct list_head *pos, *n;
  	struct fb_modelist *modelist;
  	struct fb_videomode *m, mode;
  	int err = 1;
  
  	list_for_each_safe(pos, n, &info->modelist) {
  		modelist = list_entry(pos, struct fb_modelist, list);
  		m = &modelist->mode;
  		fb_videomode_to_var(&var, m);
  		var.activate = FB_ACTIVATE_TEST;
  		err = fb_set_var(info, &var);
  		fb_var_to_videomode(&mode, &var);
  		if (err || !fb_mode_is_equal(m, &mode)) {
  			list_del(pos);
  			kfree(pos);
  		}
  	}
  
  	err = 1;
  
  	if (!list_empty(&info->modelist)) {
513adb586   Andrea Righi   fbdev: fix info->...
1783
1784
  		if (!lock_fb_info(info))
  			return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1785
  		event.info = info;
256154fbc   Antonino A. Daplas   [PATCH] fbdev: st...
1786
  		err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
513adb586   Andrea Righi   fbdev: fix info->...
1787
  		unlock_fb_info(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1788
1789
1790
1791
  	}
  
  	return err;
  }
0128beeee   Helge Deller   [PATCH] constify ...
1792
1793
  static char *video_options[FB_MAX] __read_mostly;
  static int ofonly __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
  
  /**
   * fb_get_options - get kernel boot parameters
   * @name:   framebuffer name as it would appear in
   *          the boot parameter line
   *          (video=<name>:<options>)
   * @option: the option will be stored here
   *
   * NOTE: Needed to maintain backwards compatibility
   */
  int fb_get_options(char *name, char **option)
  {
  	char *opt, *options = NULL;
a67ef278e   Denys Vlasenko   drivers/video/fbm...
1807
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1808
1809
1810
1811
1812
1813
1814
1815
1816
  	int name_len = strlen(name), i;
  
  	if (name_len && ofonly && strncmp(name, "offb", 4))
  		retval = 1;
  
  	if (name_len && !retval) {
  		for (i = 0; i < FB_MAX; i++) {
  			if (video_options[i] == NULL)
  				continue;
a67ef278e   Denys Vlasenko   drivers/video/fbm...
1817
  			if (!video_options[i][0])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
  				continue;
  			opt = video_options[i];
  			if (!strncmp(name, opt, name_len) &&
  			    opt[name_len] == ':')
  				options = opt + name_len + 1;
  		}
  	}
  	if (options && !strncmp(options, "off", 3))
  		retval = 1;
  
  	if (option)
  		*option = options;
  
  	return retval;
  }
bc6d7fdf4   Andrew Morton   [PATCH] fbdev: vi...
1833
  #ifndef MODULE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
  /**
   *	video_setup - process command line options
   *	@options: string of options
   *
   *	Process command line options for frame buffer subsystem.
   *
   *	NOTE: This function is a __setup and __init function.
   *            It only stores the options.  Drivers have to call
   *            fb_get_options() as necessary.
   *
   *	Returns zero.
   *
   */
75c96f858   Adrian Bunk   [PATCH] make some...
1847
  static int __init video_setup(char *options)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
  {
  	int i, global = 0;
  
  	if (!options || !*options)
   		global = 1;
  
   	if (!global && !strncmp(options, "ofonly", 6)) {
   		ofonly = 1;
   		global = 1;
   	}
f80330357   Dave Airlie   fb: change rules ...
1858
   	if (!global && !strchr(options, ':')) {
9a054fbac   Geert Uytterhoeven   fb: move and rena...
1859
   		fb_mode_option = options;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
   		global = 1;
   	}
  
   	if (!global) {
   		for (i = 0; i < FB_MAX; i++) {
   			if (video_options[i] == NULL) {
   				video_options[i] = options;
   				break;
   			}
  
  		}
  	}
9b41046cd   OGAWA Hirofumi   [PATCH] Don't pas...
1872
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1873
1874
  }
  __setup("video=", video_setup);
bc6d7fdf4   Andrew Morton   [PATCH] fbdev: vi...
1875
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1876
1877
1878
1879
1880
1881
1882
1883
1884
  
      /*
       *  Visible symbols for modules
       */
  
  EXPORT_SYMBOL(register_framebuffer);
  EXPORT_SYMBOL(unregister_framebuffer);
  EXPORT_SYMBOL(num_registered_fb);
  EXPORT_SYMBOL(registered_fb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1885
1886
1887
1888
1889
  EXPORT_SYMBOL(fb_show_logo);
  EXPORT_SYMBOL(fb_set_var);
  EXPORT_SYMBOL(fb_blank);
  EXPORT_SYMBOL(fb_pan_display);
  EXPORT_SYMBOL(fb_get_buffer_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890
  EXPORT_SYMBOL(fb_set_suspend);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1891
  EXPORT_SYMBOL(fb_get_options);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
1893
  
  MODULE_LICENSE("GPL");