14 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <linux/kernel.h>
21 #include <linux/slab.h>
23 #include <linux/mman.h>
32 #include <linux/device.h>
43 #define FBPIXMAPSIZE (1024 * 8)
49 static struct fb_info *get_fb_info(
unsigned int idx)
69 if (fb_info->
fbops->fb_destroy)
70 fb_info->
fbops->fb_destroy(fb_info);
97 if (var->
green.length == var->
blue.length &&
98 var->
green.length == var->
red.length &&
100 var->
green.offset == var->
red.offset)
101 depth = var->
green.length;
103 depth = var->
green.length + var->
red.length +
116 __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height);
126 for (i = height; i--; ) {
127 for (j = 0; j <
idx; j++) {
130 tmp |= *src >> shift_low;
132 tmp = *src << shift_high;
138 tmp |= *src >> shift_low;
140 if (shift_high < mod) {
141 tmp = *src << shift_high;
164 info->
fbops->fb_sync(info);
177 info->
fbops->fb_sync(info);
188 static inline unsigned safe_shift(
unsigned d,
int n)
190 return n < 0 ? d >> -n : d <<
n;
193 static void fb_set_logocmap(
struct fb_info *
info,
197 u16 palette_green[16];
198 u16 palette_blue[16];
201 const unsigned char *clut = logo->
clut;
203 palette_cmap.start = 0;
204 palette_cmap.len = 16;
205 palette_cmap.red = palette_red;
206 palette_cmap.green = palette_green;
207 palette_cmap.blue = palette_blue;
208 palette_cmap.transp =
NULL;
210 for (i = 0; i < logo->
clutsize; i +=
n) {
215 palette_cmap.start = 32 +
i;
216 palette_cmap.len =
n;
217 for (j = 0; j <
n; ++
j) {
218 palette_cmap.red[
j] = clut[0] << 8 | clut[0];
219 palette_cmap.green[
j] = clut[1] << 8 | clut[1];
220 palette_cmap.blue[
j] = clut[2] << 8 | clut[2];
227 static void fb_set_logo_truepalette(
struct fb_info *info,
231 static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
232 unsigned char redmask, greenmask, bluemask;
233 int redshift, greenshift, blueshift;
235 const unsigned char *clut = logo->
clut;
242 redmask = mask[info->
var.red.length < 8 ? info->
var.red.length : 8];
243 greenmask = mask[info->
var.green.length < 8 ? info->
var.green.length : 8];
244 bluemask = mask[info->
var.blue.length < 8 ? info->
var.blue.length : 8];
245 redshift = info->
var.red.offset - (8 - info->
var.red.length);
246 greenshift = info->
var.green.offset - (8 - info->
var.green.length);
247 blueshift = info->
var.blue.offset - (8 - info->
var.blue.length);
249 for ( i = 0; i < logo->
clutsize; i++) {
250 palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
251 safe_shift((clut[1] & greenmask), greenshift) |
252 safe_shift((clut[2] & bluemask), blueshift));
257 static void fb_set_logo_directpalette(
struct fb_info *info,
261 int redshift, greenshift, blueshift;
264 redshift = info->
var.red.offset;
265 greenshift = info->
var.green.offset;
266 blueshift = info->
var.blue.offset;
268 for (i = 32; i < 32 + logo->
clutsize; i++)
269 palette[i] = i << redshift | i << greenshift | i << blueshift;
272 static void fb_set_logo(
struct fb_info *info,
295 fg = ~((
u8) (0xfff << info->
var.green.length));
299 for (i = 0; i < logo->
height; i++)
300 for (j = 0; j < logo->
width; src++) {
303 if (j < logo->
width) {
304 *dst++ = *src & 0x0f;
310 for (i = 0; i < logo->
height; i++) {
311 for (j = 0; j < logo->
width; src++) {
313 for (k = 7; k >= 0; k--) {
314 *dst++ = ((
d >>
k) & 1) ? fg : 0;
349 static struct logo_data {
351 int needs_directpalette;
352 int needs_truepalette;
363 for (i = size; i--; )
367 static void fb_rotate_logo_cw(
const u8 *in,
u8 *out,
u32 width,
u32 height)
369 int i,
j,
h = height - 1;
371 for (i = 0; i <
height; i++)
372 for (j = 0; j <
width; j++)
373 out[height * j + h - i] = *in++;
376 static void fb_rotate_logo_ccw(
const u8 *in,
u8 *out,
u32 width,
u32 height)
378 int i,
j,
w = width - 1;
380 for (i = 0; i <
height; i++)
381 for (j = 0; j <
width; j++)
382 out[height * (w - j) +
i] = *in++;
385 static void fb_rotate_logo(
struct fb_info *info,
u8 *dst,
391 fb_rotate_logo_ud(image->
data, dst, image->
width,
396 fb_rotate_logo_cw(image->
data, dst, image->
width,
402 image->
dy = image->
dx;
405 fb_rotate_logo_ccw(image->
data, dst, image->
width,
411 image->
dx = image->
dy;
418 static void fb_do_show_logo(
struct fb_info *info,
struct fb_image *image,
419 int rotate,
unsigned int num)
425 x < num && image->
dx + image->
width <= info->
var.xres;
427 info->
fbops->fb_imageblit(info, image);
431 for (x = 0; x < num && image->
dx >= 0; x++) {
432 info->
fbops->fb_imageblit(info, image);
437 x < num && image->
dy + image->
height <= info->
var.yres;
439 info->
fbops->fb_imageblit(info, image);
443 for (x = 0; x < num && image->
dy >= 0; x++) {
444 info->
fbops->fb_imageblit(info, image);
450 static int fb_show_logo_line(
struct fb_info *info,
int rotate,
455 unsigned char *logo_new =
NULL, *logo_rotate =
NULL;
466 if (fb_logo.needs_cmapreset)
467 fb_set_logocmap(info, logo);
469 if (fb_logo.needs_truepalette ||
470 fb_logo.needs_directpalette) {
475 if (fb_logo.needs_truepalette)
476 fb_set_logo_truepalette(info, logo, palette);
478 fb_set_logo_directpalette(info, logo, palette);
484 if (fb_logo.depth <= 4) {
486 if (logo_new ==
NULL) {
488 if (saved_pseudo_palette)
492 image.
data = logo_new;
493 fb_set_logo(info, logo, logo_new, fb_logo.depth);
505 fb_rotate_logo(info, logo_rotate, &image, rotate);
508 fb_do_show_logo(info, &image, rotate, n);
511 if (saved_pseudo_palette !=
NULL)
519 #ifdef CONFIG_FB_LOGO_EXTRA
521 #define FB_LOGO_EX_NUM_MAX 10
522 static struct logo_data_extra {
525 } fb_logo_ex[FB_LOGO_EX_NUM_MAX];
526 static unsigned int fb_logo_ex_num;
528 void fb_append_extra_logo(
const struct linux_logo *logo,
unsigned int n)
530 if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
533 fb_logo_ex[fb_logo_ex_num].logo = logo;
534 fb_logo_ex[fb_logo_ex_num].n =
n;
538 static int fb_prepare_extra_logos(
struct fb_info *info,
unsigned int height,
547 for (i = 0; i < fb_logo_ex_num; i++) {
548 if (fb_logo_ex[i].logo->
type != fb_logo.logo->type) {
549 fb_logo_ex[
i].logo =
NULL;
552 height += fb_logo_ex[
i].logo->height;
554 height -= fb_logo_ex[
i].logo->height;
562 static int fb_show_extra_logos(
struct fb_info *info,
int y,
int rotate)
566 for (i = 0; i < fb_logo_ex_num; i++)
567 y += fb_show_logo_line(info, rotate,
568 fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
575 static inline int fb_prepare_extra_logos(
struct fb_info *info,
582 static inline int fb_show_extra_logos(
struct fb_info *info,
int y,
int rotate)
595 memset(&fb_logo, 0,
sizeof(
struct logo_data));
602 depth = info->
var.blue.length;
603 if (info->
var.red.length < depth)
604 depth = info->
var.red.length;
605 if (info->
var.green.length < depth)
606 depth = info->
var.green.length;
622 yres = info->
var.yres;
624 yres = info->
var.xres;
626 if (fb_logo.logo->height > yres) {
640 if (fb_logo.depth > 4 && depth > 4) {
641 switch (info->
fix.visual) {
643 fb_logo.needs_truepalette = 1;
646 fb_logo.needs_directpalette = 1;
647 fb_logo.needs_cmapreset = 1;
650 fb_logo.needs_cmapreset = 1;
655 return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
662 y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
664 y = fb_show_extra_logos(info, y, rotate);
673 static void *fb_seq_start(
struct seq_file *
m, loff_t *
pos)
679 static void *fb_seq_next(
struct seq_file *m,
void *
v, loff_t *pos)
685 static void fb_seq_stop(
struct seq_file *m,
void *v)
690 static int fb_seq_show(
struct seq_file *m,
void *v)
692 int i = *(loff_t *)v;
701 .start = fb_seq_start,
709 return seq_open(file, &proc_fb_seq_ops);
714 .open = proc_fb_open,
728 static struct fb_info *file_fb_info(
struct file *
file)
731 int fbidx = iminor(inode);
740 fb_read(
struct file *file,
char __user *
buf,
size_t count, loff_t *ppos)
742 unsigned long p = *ppos;
743 struct fb_info *info = file_fb_info(file);
755 if (info->
fbops->fb_read)
756 return info->
fbops->fb_read(info, buf, count, ppos);
761 total_size = info->
fix.smem_len;
766 if (count >= total_size)
769 if (count + p > total_size)
770 count = total_size -
p;
779 if (info->
fbops->fb_sync)
780 info->
fbops->fb_sync(info);
805 fb_write(
struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
807 unsigned long p = *ppos;
808 struct fb_info *info = file_fb_info(file);
811 int c, cnt = 0,
err = 0;
820 if (info->
fbops->fb_write)
821 return info->
fbops->fb_write(info, buf, count, ppos);
826 total_size = info->
fix.smem_len;
831 if (count > total_size) {
836 if (count + p > total_size) {
840 count = total_size -
p;
850 if (info->
fbops->fb_sync)
851 info->
fbops->fb_sync(info);
873 return (cnt) ? cnt :
err;
880 unsigned int yres = info->
var.yres;
897 if (err || !info->
fbops->fb_pan_display ||
898 var->
yoffset > info->
var.yres_virtual - yres ||
902 if ((err = info->
fbops->fb_pan_display(var, info)))
921 memset(&fbcaps, 0,
sizeof(fbcaps));
926 info->
fbops->fb_get_caps(info, &fbcaps, var);
928 if (((fbcaps.x ^
caps.x) &
caps.x) ||
930 (fbcaps.len <
caps.len))
975 if (var->
red.offset || var->
green.offset ||
977 var->
red.length || var->
green.length ||
979 var->
red.msb_right || var->
green.msb_right ||
984 if (!info->
fbops->fb_check_var) {
989 ret = info->
fbops->fb_check_var(var, info);
998 if (info->
fbops->fb_get_caps) {
999 ret = fb_check_caps(info, var, activate);
1005 old_var = info->
var;
1008 if (info->
fbops->fb_set_par) {
1009 ret = info->
fbops->fb_set_par(info);
1012 info->
var = old_var;
1014 "fb_set_par error, "
1015 "error code: %d\n", ret);
1034 info->
flags &= ~FBINFO_MISC_USEREVENT;
1056 event.data = ␣
1060 if (info->
fbops->fb_blank)
1061 ret = info->
fbops->fb_blank(blank, info);
1077 static long do_fb_ioctl(
struct fb_info *info,
unsigned int cmd,
1095 unlock_fb_info(info);
1109 unlock_fb_info(info);
1117 unlock_fb_info(info);
1131 cmap_from = info->
cmap;
1132 unlock_fb_info(info);
1143 unlock_fb_info(info);
1155 con2fb.framebuffer = -1;
1156 event.data = &con2fb;
1161 unlock_fb_info(info);
1169 if (con2fb.framebuffer < 0 || con2fb.framebuffer >=
FB_MAX)
1171 if (!registered_fb[con2fb.framebuffer])
1172 request_module(
"fb%d", con2fb.framebuffer);
1173 if (!registered_fb[con2fb.framebuffer]) {
1177 event.data = &con2fb;
1182 unlock_fb_info(info);
1192 unlock_fb_info(info);
1199 ret = fb->
fb_ioctl(info, cmd, arg);
1202 unlock_fb_info(info);
1207 static long fb_ioctl(
struct file *file,
unsigned int cmd,
unsigned long arg)
1209 struct fb_info *info = file_fb_info(file);
1213 return do_fb_ioctl(info, cmd, arg);
1216 #ifdef CONFIG_COMPAT
1217 struct fb_fix_screeninfo32 {
1243 static int fb_getput_cmap(
struct fb_info *info,
unsigned int cmd,
1247 struct fb_cmap32
__user *cmap32;
1252 cmap32 = compat_ptr(arg);
1257 if (
get_user(data, &cmap32->red) ||
1267 err = do_fb_ioctl(info, cmd, (
unsigned long) cmap);
1279 struct fb_fix_screeninfo32 __user *fix32)
1287 err |=
put_user(data, &fix32->smem_start);
1299 err |=
put_user(data, &fix32->mmio_start);
1309 static int fb_get_fscreeninfo(
struct fb_info *info,
unsigned int cmd,
1314 struct fb_fix_screeninfo32
__user *fix32;
1317 fix32 = compat_ptr(arg);
1321 err = do_fb_ioctl(info, cmd, (
unsigned long) &fix);
1325 err = do_fscreeninfo_to_user(&fix, fix32);
1330 static long fb_compat_ioctl(
struct file *file,
unsigned int cmd,
1333 struct fb_info *info = file_fb_info(file);
1346 arg = (
unsigned long) compat_ptr(arg);
1348 ret = do_fb_ioctl(info, cmd, arg);
1352 ret = fb_get_fscreeninfo(info, cmd, arg);
1357 ret = fb_getput_cmap(info, cmd, arg);
1372 struct fb_info *info = file_fb_info(file);
1375 unsigned long start;
1395 start = info->
fix.smem_start;
1400 if (info->
var.accel_flags) {
1404 start = info->
fix.mmio_start;
1423 fb_open(
struct inode *inode,
struct file *file)
1427 int fbidx = iminor(inode);
1428 struct fb_info *
info;
1431 info = get_fb_info(fbidx);
1433 request_module(
"fb%d", fbidx);
1434 info = get_fb_info(fbidx);
1439 return PTR_ERR(info);
1442 if (!try_module_get(info->
fbops->owner)) {
1447 if (info->
fbops->fb_open) {
1448 res = info->
fbops->fb_open(info,1);
1450 module_put(info->
fbops->owner);
1452 #ifdef CONFIG_FB_DEFERRED_IO
1464 fb_release(
struct inode *inode,
struct file *file)
1471 if (info->
fbops->fb_release)
1472 info->
fbops->fb_release(info,1);
1473 module_put(info->
fbops->owner);
1483 .unlocked_ioctl = fb_ioctl,
1484 #ifdef CONFIG_COMPAT
1485 .compat_ioctl = fb_compat_ioctl,
1489 .release = fb_release,
1490 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
1493 #ifdef CONFIG_FB_DEFERRED_IO
1502 static int fb_check_foreignness(
struct fb_info *fi)
1515 pr_err(
"%s: enable CONFIG_FB_BIG_ENDIAN to "
1516 "support this framebuffer\n", fi->
fix.id);
1519 pr_err(
"%s: enable CONFIG_FB_LITTLE_ENDIAN to "
1520 "support this framebuffer\n", fi->
fix.id);
1527 static bool apertures_overlap(
struct aperture *
gen,
struct aperture *
hw)
1530 if (gen->base == hw->base)
1533 if (gen->base > hw->base && gen->base < hw->base + hw->size)
1538 static bool fb_do_apertures_overlap(
struct apertures_struct *gena,
1539 struct apertures_struct *hwa)
1545 for (i = 0; i < hwa->count; ++
i) {
1546 struct aperture *h = &hwa->ranges[
i];
1547 for (j = 0; j < gena->count; ++
j) {
1548 struct aperture *
g = &gena->ranges[
j];
1550 (
unsigned long long)g->base,
1551 (
unsigned long long)g->size,
1552 (
unsigned long long)h->base,
1553 (
unsigned long long)h->size);
1554 if (apertures_overlap(g, h))
1562 static int do_unregister_framebuffer(
struct fb_info *fb_info);
1564 #define VGA_FB_PHYS 0xA0000
1565 static void do_remove_conflicting_framebuffers(
struct apertures_struct *
a,
1571 for (i = 0 ; i <
FB_MAX; i++) {
1572 struct apertures_struct *gen_aper;
1580 if (fb_do_apertures_overlap(gen_aper, a) ||
1581 (primary && gen_aper && gen_aper->count &&
1585 "%s vs %s - removing generic driver\n",
1592 static int do_register_framebuffer(
struct fb_info *fb_info)
1598 if (fb_check_foreignness(fb_info))
1601 do_remove_conflicting_framebuffers(fb_info->
apertures, fb_info->
fix.id,
1604 if (num_registered_fb ==
FB_MAX)
1608 for (i = 0 ; i <
FB_MAX; i++)
1609 if (!registered_fb[i])
1618 if (IS_ERR(fb_info->
dev)) {
1620 printk(
KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->
dev));
1627 if (fb_info->
pixmap.addr) {
1629 fb_info->
pixmap.buf_align = 1;
1630 fb_info->
pixmap.scan_align = 1;
1631 fb_info->
pixmap.access_align = 32;
1635 fb_info->
pixmap.offset = 0;
1637 if (!fb_info->
pixmap.blit_x)
1640 if (!fb_info->
pixmap.blit_y)
1644 INIT_LIST_HEAD(&fb_info->
modelist);
1654 unlock_fb_info(fb_info);
1658 static int do_unregister_framebuffer(
struct fb_info *fb_info)
1664 if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1671 unlock_fb_info(fb_info);
1677 if (fb_info->
pixmap.addr &&
1688 put_fb_info(fb_info);
1712 do_remove_conflicting_framebuffers(a, name, primary);
1732 ret = do_register_framebuffer(fb_info);
1760 ret = do_unregister_framebuffer(fb_info);
1801 proc_create(
"fb", 0,
NULL, &fb_proc_fops);
1803 if (register_chrdev(
FB_MAJOR,
"fb",&fb_fops))
1807 if (IS_ERR(fb_class)) {
1842 m = &modelist->
mode;
1855 if (!list_empty(&info->
modelist)) {
1860 unlock_fb_info(info);
1884 if (name_len && ofonly &&
strncmp(name,
"offb", 4))
1887 if (name_len && !retval) {
1888 for (i = 0; i <
FB_MAX; i++) {
1889 if (video_options[i] ==
NULL)
1891 if (!video_options[i][0])
1893 opt = video_options[
i];
1894 if (!
strncmp(name, opt, name_len) &&
1895 opt[name_len] ==
':')
1896 options = opt + name_len + 1;
1899 if (options && !
strncmp(options,
"off", 3))
1926 if (!options || !*options)
1929 if (!global && !
strncmp(options,
"ofonly", 6)) {
1934 if (!global && !
strchr(options,
':')) {
1940 for (i = 0; i <
FB_MAX; i++) {
1941 if (video_options[i] ==
NULL) {
1951 __setup(
"video=", video_setup);