OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [video/] [fbmem.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.