Subversion Repositories shark

Rev

Rev 482 | Rev 484 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
466 giacomo 1
/*
2
 *  linux/drivers/video/fbmem.c
3
 *
4
 *  Copyright (C) 1994 Martin Schaller
5
 *
6
 *      2001 - Documented with DocBook
7
 *      - Brad Douglas <brad@neruo.com>
8
 *
9
 * This file is subject to the terms and conditions of the GNU General Public
10
 * License.  See the file COPYING in the main directory of this archive
11
 * for more details.
12
 */
13
 
14
#include <linuxcomp.h>
15
 
16
#include <linux/config.h>
17
#include <linux/module.h>
18
 
19
#include <linux/types.h>
20
#include <linux/errno.h>
21
#include <linux/sched.h>
22
#include <linux/smp_lock.h>
23
#include <linux/kernel.h>
24
#include <linux/major.h>
25
#include <linux/slab.h>
26
#include <linux/mm.h>
27
#include <linux/mman.h>
28
#include <linux/tty.h>
29
#include <linux/init.h>
30
#include <linux/linux_logo.h>
31
#include <linux/proc_fs.h>
32
#ifdef CONFIG_KMOD
33
#include <linux/kmod.h>
34
#endif
35
#include <linux/devfs_fs_kernel.h>
36
 
37
#if defined(__mc68000__) || defined(CONFIG_APUS)
38
#include <asm/setup.h>
39
#endif
40
 
41
#include <asm/io.h>
42
#include <asm/uaccess.h>
43
#include <asm/page.h>
44
#include <asm/pgtable.h>
45
 
46
#include <linux/fb.h>
47
 
48
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
49
#include "console/fbcon.h"
50
#endif
51
    /*
52
     *  Frame buffer device initialization and setup routines
53
     */
54
 
55
extern int acornfb_init(void);
56
extern int acornfb_setup(char*);
57
extern int amifb_init(void);
58
extern int amifb_setup(char*);
59
extern int anakinfb_init(void);
60
extern int atafb_init(void);
61
extern int atafb_setup(char*);
62
extern int macfb_init(void);
63
extern int macfb_setup(char*);
64
extern int cyberfb_init(void);
65
extern int cyberfb_setup(char*);
66
extern int pm2fb_init(void);
67
extern int pm2fb_setup(char*);
68
extern int pm3fb_init(void);
69
extern int pm3fb_setup(char*);
70
extern int clps711xfb_init(void);
71
extern int cyber2000fb_init(void);
72
extern int cyber2000fb_setup(char*);
73
extern int retz3fb_init(void);
74
extern int retz3fb_setup(char*);
75
extern int clgenfb_init(void);
76
extern int clgenfb_setup(char*);
77
extern int hitfb_init(void);
78
extern int vfb_init(void);
79
extern int vfb_setup(char*);
80
extern int offb_init(void);
81
extern int atyfb_init(void);
82
extern int atyfb_setup(char*);
83
extern int aty128fb_init(void);
84
extern int aty128fb_setup(char*);
85
extern int neofb_init(void);
86
extern int neofb_setup(char*);
87
extern int igafb_init(void);
88
extern int igafb_setup(char*);
89
extern int imsttfb_init(void);
90
extern int imsttfb_setup(char*);
91
extern int dnfb_init(void);
92
extern int tgafb_init(void);
93
extern int tgafb_setup(char*);
94
extern int virgefb_init(void);
95
extern int virgefb_setup(char*);
96
extern int resolver_video_setup(char*);
97
extern int s3triofb_init(void);
98
extern int vesafb_init(void);
99
extern int vesafb_setup(char*);
100
extern int vga16fb_init(void);
101
extern int vga16fb_setup(char*);
102
extern int hgafb_init(void);
103
extern int hgafb_setup(char*);
104
extern int matroxfb_init(void);
105
extern int matroxfb_setup(char*);
106
extern int hpfb_init(void);
107
extern int control_init(void);
108
extern int control_setup(char*);
109
extern int platinum_init(void);
110
extern int platinum_setup(char*);
111
extern int valkyriefb_init(void);
112
extern int valkyriefb_setup(char*);
113
extern int chips_init(void);
114
extern int g364fb_init(void);
115
extern int sa1100fb_init(void);
116
extern int fm2fb_init(void);
117
extern int fm2fb_setup(char*);
118
extern int q40fb_init(void);
119
extern int sun3fb_init(void);
120
extern int sun3fb_setup(char *);
121
extern int sgivwfb_init(void);
122
extern int sgivwfb_setup(char*);
123
extern int rivafb_init(void);
124
extern int rivafb_setup(char*);
125
extern int tdfxfb_init(void);
126
extern int tdfxfb_setup(char*);
127
extern int tridentfb_init(void);
128
extern int tridentfb_setup(char*);
129
extern int sisfb_init(void);
130
extern int sisfb_setup(char*);
131
extern int stifb_init(void);
132
extern int stifb_setup(char*);
133
extern int pmagbafb_init(void);
134
extern int pmagbbfb_init(void);
135
extern int maxinefb_init(void);
136
extern int tx3912fb_init(void);
137
extern int tx3912fb_setup(char*);
138
extern int radeonfb_init(void);
139
extern int radeonfb_setup(char*);
140
extern int e1355fb_init(void);
141
extern int e1355fb_setup(char*);
142
extern int pvr2fb_init(void);
143
extern int pvr2fb_setup(char*);
144
extern int sstfb_init(void);
145
extern int sstfb_setup(char*);
146
extern int i810fb_init(void);
147
extern int i810fb_setup(char*);
148
extern int ffb_init(void);
149
extern int ffb_setup(char*);
150
extern int cg6_init(void);
151
extern int cg6_setup(char*);
152
extern int cg3_init(void);
153
extern int cg3_setup(char*);
154
extern int bw2_init(void);
155
extern int bw2_setup(char*);
156
extern int cg14_init(void);
157
extern int cg14_setup(char*);
158
extern int p9100_init(void);
159
extern int p9100_setup(char*);
160
extern int tcx_init(void);
161
extern int tcx_setup(char*);
162
extern int leo_init(void);
163
extern int leo_setup(char*);
164
 
165
static struct {
166
        const char *name;
167
        int (*init)(void);
168
        int (*setup)(char*);
169
} fb_drivers[] __initdata = {
170
 
171
        /*
172
         * Chipset specific drivers that use resource management
173
         */
174
#ifdef CONFIG_FB_RETINAZ3
175
        { "retz3fb", retz3fb_init, retz3fb_setup },
176
#endif
177
#ifdef CONFIG_FB_AMIGA
178
        { "amifb", amifb_init, amifb_setup },
179
#endif
180
#ifdef CONFIG_FB_ANAKIN
181
        { "anakinfb", anakinfb_init, NULL },
182
#endif
183
#ifdef CONFIG_FB_CLPS711X
184
        { "clps711xfb", clps711xfb_init, NULL },
185
#endif
186
#ifdef CONFIG_FB_CYBER
187
        { "cyberfb", cyberfb_init, cyberfb_setup },
188
#endif
189
#ifdef CONFIG_FB_CYBER2000
190
        { "cyber2000fb", cyber2000fb_init, cyber2000fb_setup },
191
#endif
192
#ifdef CONFIG_FB_PM2
193
        { "pm2fb", pm2fb_init, pm2fb_setup },
194
#endif
195
#ifdef CONFIG_FB_PM3
196
        { "pm3fb", pm3fb_init, pm3fb_setup },
197
#endif           
198
#ifdef CONFIG_FB_CLGEN
199
        { "clgenfb", clgenfb_init, clgenfb_setup },
200
#endif
201
#ifdef CONFIG_FB_ATY
202
        { "atyfb", atyfb_init, atyfb_setup },
203
#endif
204
#ifdef CONFIG_FB_MATROX
205
        { "matroxfb", matroxfb_init, matroxfb_setup },
206
#endif
207
#ifdef CONFIG_FB_ATY128
208
        { "aty128fb", aty128fb_init, aty128fb_setup },
209
#endif
210
#ifdef CONFIG_FB_NEOMAGIC
211
        { "neofb", neofb_init, neofb_setup },
212
#endif
213
#ifdef CONFIG_FB_VIRGE
214
        { "virgefb", virgefb_init, virgefb_setup },
215
#endif
216
#ifdef CONFIG_FB_RIVA
217
        { "rivafb", rivafb_init, rivafb_setup },
218
#endif
219
#ifdef CONFIG_FB_3DFX
220
        { "tdfxfb", tdfxfb_init, tdfxfb_setup },
221
#endif
222
#ifdef CONFIG_FB_RADEON
223
        { "radeonfb", radeonfb_init, radeonfb_setup },
224
#endif
225
#ifdef CONFIG_FB_CONTROL
226
        { "controlfb", control_init, control_setup },
227
#endif
228
#ifdef CONFIG_FB_PLATINUM
229
        { "platinumfb", platinum_init, platinum_setup },
230
#endif
231
#ifdef CONFIG_FB_VALKYRIE
232
        { "valkyriefb", valkyriefb_init, valkyriefb_setup },
233
#endif
234
#ifdef CONFIG_FB_CT65550
235
        { "chipsfb", chips_init, NULL },
236
#endif
237
#ifdef CONFIG_FB_IMSTT
238
        { "imsttfb", imsttfb_init, imsttfb_setup },
239
#endif
240
#ifdef CONFIG_FB_S3TRIO
241
        { "s3triofb", s3triofb_init, NULL },
242
#endif 
243
#ifdef CONFIG_FB_FM2
244
        { "fm2fb", fm2fb_init, fm2fb_setup },
245
#endif 
246
#ifdef CONFIG_FB_SIS
247
        { "sisfb", sisfb_init, sisfb_setup },
248
#endif
249
#ifdef CONFIG_FB_TRIDENT
250
        { "tridentfb", tridentfb_init, tridentfb_setup },
251
#endif
252
#ifdef CONFIG_FB_I810
253
        { "i810fb", i810fb_init, i810fb_setup },
254
#endif  
255
#ifdef CONFIG_FB_STI
256
        { "stifb", stifb_init, stifb_setup },
257
#endif
258
#ifdef CONFIG_FB_FFB
259
        { "ffb", ffb_init, ffb_setup },
260
#endif
261
#ifdef CONFIG_FB_CG6
262
        { "cg6fb", cg6_init, cg6_setup },
263
#endif
264
#ifdef CONFIG_FB_CG3
265
        { "cg3fb", cg3_init, cg3_setup },
266
#endif
267
#ifdef CONFIG_FB_BW2
268
        { "bw2fb", bw2_init, bw2_setup },
269
#endif
270
#ifdef CONFIG_FB_CG14
271
        { "cg14fb", cg14_init, cg14_setup },
272
#endif
273
#ifdef CONFIG_FB_P9100
274
        { "p9100fb", p9100_init, p9100_setup },
275
#endif
276
#ifdef CONFIG_FB_TCX
277
        { "tcxfb", tcx_init, tcx_setup },
278
#endif
279
#ifdef CONFIG_FB_LEO
280
        { "leofb", leo_init, leo_setup },
281
#endif
282
 
283
        /*
284
         * Generic drivers that are used as fallbacks
285
         *
286
         * These depend on resource management and must be initialized
287
         * _after_ all other frame buffer devices that use resource
288
         * management!
289
         */
290
 
291
#ifdef CONFIG_FB_OF
292
        { "offb", offb_init, NULL },
293
#endif
294
#ifdef CONFIG_FB_VESA
295
        { "vesafb", vesafb_init, vesafb_setup },
296
#endif 
297
 
298
        /*
299
         * Chipset specific drivers that don't use resource management (yet)
300
         */
301
 
302
#ifdef CONFIG_FB_SGIVW
303
        { "sgivwfb", sgivwfb_init, sgivwfb_setup },
304
#endif
305
#ifdef CONFIG_FB_ACORN
306
        { "acornfb", acornfb_init, acornfb_setup },
307
#endif
308
#ifdef CONFIG_FB_ATARI
309
        { "atafb", atafb_init, atafb_setup },
310
#endif
311
#ifdef CONFIG_FB_MAC
312
        { "macfb", macfb_init, macfb_setup },
313
#endif
314
#ifdef CONFIG_FB_HGA
315
        { "hgafb", hgafb_init, hgafb_setup },
316
#endif 
317
#ifdef CONFIG_FB_IGA
318
        { "igafb", igafb_init, igafb_setup },
319
#endif
320
#ifdef CONFIG_APOLLO
321
        { "apollofb", dnfb_init, NULL },
322
#endif
323
#ifdef CONFIG_FB_Q40
324
        { "q40fb", q40fb_init, NULL },
325
#endif
326
#ifdef CONFIG_FB_TGA
327
        { "tgafb", tgafb_init, tgafb_setup },
328
#endif
329
#ifdef CONFIG_FB_HP300
330
        { "hpfb", hpfb_init, NULL },
331
#endif 
332
#ifdef CONFIG_FB_G364
333
        { "g364fb", g364fb_init, NULL },
334
#endif
335
#ifdef CONFIG_FB_SA1100
336
        { "sa1100fb", sa1100fb_init, NULL },
337
#endif
338
#ifdef CONFIG_FB_SUN3
339
        { "sun3fb", sun3fb_init, sun3fb_setup },
340
#endif
341
#ifdef CONFIG_FB_HIT
342
        { "hitfb", hitfb_init, NULL },
343
#endif
344
#ifdef CONFIG_FB_TX3912
345
        { "tx3912fb", tx3912fb_init, tx3912fb_setup },
346
#endif
347
#ifdef CONFIG_FB_E1355
348
        { "e1355fb", e1355fb_init, e1355fb_setup },
349
#endif
350
#ifdef CONFIG_FB_PVR2
351
        { "pvr2fb", pvr2fb_init, pvr2fb_setup },
352
#endif
353
#ifdef CONFIG_FB_PMAG_BA
354
        { "pmagbafb", pmagbafb_init, NULL },
355
#endif          
356
#ifdef CONFIG_FB_PMAGB_B
357
        { "pmagbbfb", pmagbbfb_init, NULL },
358
#endif
359
#ifdef CONFIG_FB_MAXINE
360
        { "maxinefb", maxinefb_init, NULL },
361
#endif            
362
#ifdef CONFIG_FB_VOODOO1
363
        { "sstfb", sstfb_init, sstfb_setup },
364
#endif
365
        /*
366
         * Generic drivers that don't use resource management (yet)
367
         */
368
 
369
#ifdef CONFIG_FB_VGA16
370
        { "vga16fb", vga16fb_init, vga16fb_setup },
371
#endif 
372
 
373
#ifdef CONFIG_GSP_RESOLVER
374
        /* Not a real frame buffer device... */
375
        { "resolverfb", NULL, resolver_video_setup },
376
#endif
377
 
378
#ifdef CONFIG_FB_VIRTUAL
379
        /*
380
         * Vfb must be last to avoid that it becomes your primary display if
381
         * other display devices are present
382
         */
383
        { "vfb", vfb_init, vfb_setup },
384
#endif
385
};
386
 
387
#define NUM_FB_DRIVERS  (sizeof(fb_drivers)/sizeof(*fb_drivers))
388
#define FBPIXMAPSIZE    8192
389
 
468 giacomo 390
//extern const char *global_mode_option;
466 giacomo 391
 
392
static initcall_t pref_init_funcs[FB_MAX];
393
static int num_pref_init_funcs __initdata = 0;
394
struct fb_info *registered_fb[FB_MAX];
395
int num_registered_fb;
396
 
397
#ifdef CONFIG_FB_OF
398
static int ofonly __initdata = 0;
399
#endif
400
 
401
/*
402
 * Drawing helpers.
403
 */
404
u8 sys_inbuf(u8 *src)
405
{      
406
        return *src;
407
}
408
 
409
void sys_outbuf(u8 *src, u8 *dst, unsigned int size)
410
{
411
        memcpy(dst, src, size);
412
}      
413
 
414
void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
415
                        u32 s_pitch, u32 height)
416
{
417
        int i;
418
 
419
        for (i = height; i--; ) {
420
                info->pixmap.outbuf(src, dst, s_pitch);
421
                src += s_pitch;
422
                dst += d_pitch;
423
        }
424
}
425
 
426
void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
427
                        u32 height, u32 mask, u32 shift_high, u32 shift_low,
428
                        u32 mod, u32 idx)
429
{
430
        int i, j;
431
        u8 tmp;
432
 
433
        for (i = height; i--; ) {
434
                for (j = 0; j < idx; j++) {
435
                        tmp = info->pixmap.inbuf(dst+j);
436
                        tmp &= mask;
437
                        tmp |= *src >> shift_low;
438
                        info->pixmap.outbuf(&tmp, dst+j, 1);
439
                        tmp = *src << shift_high;
440
                        info->pixmap.outbuf(&tmp, dst+j+1, 1);
441
                        src++;
442
                }
443
                tmp = info->pixmap.inbuf(dst+idx);
444
                tmp &= mask;
445
                tmp |= *src >> shift_low;
446
                info->pixmap.outbuf(&tmp, dst+idx, 1);
447
                if (shift_high < mod) {
448
                        tmp = *src << shift_high;
449
                        info->pixmap.outbuf(&tmp, dst+idx+1, 1);
450
                }      
451
                src++;
452
                dst += d_pitch;
453
        }
454
}
455
 
456
/*
457
 * we need to lock this section since fb_cursor
458
 * may use fb_imageblit()
459
 */
460
u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
461
{
462
        u32 align = info->pixmap.buf_align - 1;
463
        u32 offset, count = 1000;
464
 
465
        spin_lock(&info->pixmap.lock);
466
        offset = info->pixmap.offset + align;
467
        offset &= ~align;
468
        if (offset + size > info->pixmap.size) {
469
                while (atomic_read(&info->pixmap.count) && count--);
470
                if (info->fbops->fb_sync &&
471
                    info->pixmap.flags & FB_PIXMAP_SYNC)
472
                        info->fbops->fb_sync(info);
473
                offset = 0;
474
        }
475
        info->pixmap.offset = offset + size;
476
        atomic_inc(&info->pixmap.count);       
477
        smp_mb__after_atomic_inc();
478
        spin_unlock(&info->pixmap.lock);
479
        return offset;
480
}
481
 
482
#ifdef CONFIG_LOGO
483
#include <linux/linux_logo.h>
484
 
485
static inline unsigned safe_shift(unsigned d, int n)
486
{
487
        return n < 0 ? d >> -n : d << n;
488
}
489
 
490
static void __init fb_set_logocmap(struct fb_info *info,
491
                                   const struct linux_logo *logo)
492
{
493
        struct fb_cmap palette_cmap;
494
        u16 palette_green[16];
495
        u16 palette_blue[16];
496
        u16 palette_red[16];
497
        int i, j, n;
498
        const unsigned char *clut = logo->clut;
499
 
500
        palette_cmap.start = 0;
501
        palette_cmap.len = 16;
502
        palette_cmap.red = palette_red;
503
        palette_cmap.green = palette_green;
504
        palette_cmap.blue = palette_blue;
505
        palette_cmap.transp = NULL;
506
 
507
        for (i = 0; i < logo->clutsize; i += n) {
508
                n = logo->clutsize - i;
509
                /* palette_cmap provides space for only 16 colors at once */
510
                if (n > 16)
511
                        n = 16;
512
                palette_cmap.start = 32 + i;
513
                palette_cmap.len = n;
514
                for (j = 0; j < n; ++j) {
515
                        palette_cmap.red[j] = clut[0] << 8 | clut[0];
516
                        palette_cmap.green[j] = clut[1] << 8 | clut[1];
517
                        palette_cmap.blue[j] = clut[2] << 8 | clut[2];
518
                        clut += 3;
519
                }
520
                fb_set_cmap(&palette_cmap, 1, info);
521
        }
522
}
523
 
524
static void  __init fb_set_logo_truepalette(struct fb_info *info,
525
                                            const struct linux_logo *logo,
526
                                            u32 *palette)
527
{
528
        unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
529
        unsigned char redmask, greenmask, bluemask;
530
        int redshift, greenshift, blueshift;
531
        int i;
532
        const unsigned char *clut = logo->clut;
533
 
534
        /*
535
         * We have to create a temporary palette since console palette is only
536
         * 16 colors long.
537
         */
538
        /* Bug: Doesn't obey msb_right ... (who needs that?) */
539
        redmask   = mask[info->var.red.length   < 8 ? info->var.red.length   : 8];
540
        greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
541
        bluemask  = mask[info->var.blue.length  < 8 ? info->var.blue.length  : 8];
542
        redshift   = info->var.red.offset   - (8 - info->var.red.length);
543
        greenshift = info->var.green.offset - (8 - info->var.green.length);
544
        blueshift  = info->var.blue.offset  - (8 - info->var.blue.length);
545
 
546
        for ( i = 0; i < logo->clutsize; i++) {
547
                palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
548
                                 safe_shift((clut[1] & greenmask), greenshift) |
549
                                 safe_shift((clut[2] & bluemask), blueshift));
550
                clut += 3;
551
        }
552
}
553
 
554
static void __init fb_set_logo_directpalette(struct fb_info *info,
555
                                             const struct linux_logo *logo,
556
                                             u32 *palette)
557
{
558
        int redshift, greenshift, blueshift;
559
        int i;
560
 
561
        redshift = info->var.red.offset;
562
        greenshift = info->var.green.offset;
563
        blueshift = info->var.blue.offset;
564
 
565
        for (i = 32; i < logo->clutsize; i++)
566
                palette[i] = i << redshift | i << greenshift | i << blueshift;
567
}
568
 
569
static void __init fb_set_logo(struct fb_info *info,
570
                               const struct linux_logo *logo, u8 *dst,
571
                               int depth)
572
{
573
        int i, j, shift;
574
        const u8 *src = logo->data;
575
        u8 d, xor = 0;
576
 
577
        switch (depth) {
578
        case 4:
579
                for (i = 0; i < logo->height; i++)
580
                        for (j = 0; j < logo->width; src++) {
581
                                *dst++ = *src >> 4;
582
                                j++;
583
                                if (j < logo->width) {
584
                                        *dst++ = *src & 0x0f;
585
                                        j++;
586
                                }
587
                        }
588
                break;
589
        case ~1:
590
                xor = 0xff;
591
        case 1:
592
                for (i = 0; i < logo->height; i++) {
593
                        shift = 7;
594
                        d = *src++ ^ xor;
595
                        for (j = 0; j < logo->width; j++) {
596
                                *dst++ = (d >> shift) & 1;
597
                                shift = (shift-1) & 7;
598
                                if (shift == 7)
599
                                        d = *src++ ^ xor;
600
                        }
601
                }
602
                break;
603
        }
604
}
605
 
606
/*
607
 * Three (3) kinds of logo maps exist.  linux_logo_clut224 (>16 colors),
608
 * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors).  Depending on
609
 * the visual format and color depth of the framebuffer, the DAC, the
610
 * pseudo_palette, and the logo data will be adjusted accordingly.
611
 *
612
 * Case 1 - linux_logo_clut224:
613
 * Color exceeds the number of console colors (16), thus we set the hardware DAC
614
 * using fb_set_cmap() appropriately.  The "needs_cmapreset"  flag will be set.
615
 *
616
 * For visuals that require color info from the pseudo_palette, we also construct
617
 * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
618
 * will be set.
619
 *
620
 * Case 2 - linux_logo_vga16:
621
 * The number of colors just matches the console colors, thus there is no need
622
 * to set the DAC or the pseudo_palette.  However, the bitmap is packed, ie,
623
 * each byte contains color information for two pixels (upper and lower nibble).
624
 * To be consistent with fb_imageblit() usage, we therefore separate the two
625
 * nibbles into separate bytes. The "depth" flag will be set to 4.
626
 *
627
 * Case 3 - linux_logo_mono:
628
 * This is similar with Case 2.  Each byte contains information for 8 pixels.
629
 * We isolate each bit and expand each into a byte. The "depth" flag will
630
 * be set to 1.
631
 */
632
static struct logo_data {
633
        int depth;
634
        int needs_directpalette;
635
        int needs_truepalette;
636
        int needs_cmapreset;
637
        const struct linux_logo *logo;
638
} fb_logo;
639
 
640
int fb_prepare_logo(struct fb_info *info)
641
{
642
        memset(&fb_logo, 0, sizeof(struct logo_data));
643
 
644
        switch (info->fix.visual) {
645
        case FB_VISUAL_TRUECOLOR:
646
                if (info->var.bits_per_pixel >= 8)
647
                        fb_logo.needs_truepalette = 1;
648
                break;
649
        case FB_VISUAL_DIRECTCOLOR:
650
                if (info->var.bits_per_pixel >= 24) {
651
                        fb_logo.needs_directpalette = 1;
652
                        fb_logo.needs_cmapreset = 1;
653
                }
654
                break;
655
        case FB_VISUAL_PSEUDOCOLOR:
656
                fb_logo.needs_cmapreset = 1;
657
                break;
658
        }
659
 
660
        /* Return if no suitable logo was found */
661
        fb_logo.logo = fb_find_logo(info->var.bits_per_pixel);
662
 
663
        if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
664
                fb_logo.logo = NULL;
665
                return 0;
666
        }
667
        /* What depth we asked for might be different from what we get */
668
        if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
669
                fb_logo.depth = 8;
670
        else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
671
                fb_logo.depth = 4;
672
        else
673
                fb_logo.depth = 1;             
674
        return fb_logo.logo->height;
675
}
676
 
677
int fb_show_logo(struct fb_info *info)
678
{
679
        u32 *palette = NULL, *saved_pseudo_palette = NULL;
680
        unsigned char *logo_new = NULL;
681
        struct fb_image image;
682
        int x;
683
 
684
        /* Return if the frame buffer is not mapped */
685
        if (fb_logo.logo == NULL)
686
                return 0;
687
 
688
        image.depth = fb_logo.depth;
689
        image.data = fb_logo.logo->data;
690
 
691
        if (fb_logo.needs_cmapreset)
692
                fb_set_logocmap(info, fb_logo.logo);
693
 
694
        if (fb_logo.needs_truepalette ||
695
            fb_logo.needs_directpalette) {
696
                palette = kmalloc(256 * 4, GFP_KERNEL);
697
                if (palette == NULL)
698
                        return 0;
699
 
700
                if (fb_logo.needs_truepalette)
701
                        fb_set_logo_truepalette(info, fb_logo.logo, palette);
702
                else
703
                        fb_set_logo_directpalette(info, fb_logo.logo, palette);
704
 
705
                saved_pseudo_palette = info->pseudo_palette;
706
                info->pseudo_palette = palette;
707
        }
708
 
709
        if (fb_logo.depth == 4) {
710
                logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height,
711
                                   GFP_KERNEL);
712
                if (logo_new == NULL) {
713
                        if (palette)
714
                                kfree(palette);
715
                        if (saved_pseudo_palette)
716
                                info->pseudo_palette = saved_pseudo_palette;
717
                        return 0;
718
                }
719
                image.data = logo_new;
720
                fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
721
        }
722
 
723
        image.width = fb_logo.logo->width;
724
        image.height = fb_logo.logo->height;
725
        image.dy = 0;
726
 
727
        for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&
728
             x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
729
                image.dx = x;
730
                info->fbops->fb_imageblit(info, &image);
731
                //atomic_dec(&info->pixmap.count);
732
                //smp_mb__after_atomic_dec();
733
        }
734
 
735
        if (palette != NULL)
736
                kfree(palette);
737
        if (saved_pseudo_palette != NULL)
738
                info->pseudo_palette = saved_pseudo_palette;
739
        if (logo_new != NULL)
740
                kfree(logo_new);
741
        return fb_logo.logo->height;
742
}
743
#else
744
int fb_prepare_logo(struct fb_info *info) { return 0; }
745
int fb_show_logo(struct fb_info *info) { return 0; }
746
#endif /* CONFIG_LOGO */
747
 
748
static int fbmem_read_proc(char *buf, char **start, off_t offset,
749
                           int len, int *eof, void *private)
750
{
751
        struct fb_info **fi;
752
        int clen;
753
 
754
        clen = 0;
755
        for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
756
                if (*fi)
757
                        clen += sprintf26(buf + clen, "%d %s\n",
758
                                        (*fi)->node,
759
                                        (*fi)->fix.id);
760
        *start = buf + offset;
761
        if (clen > offset)
762
                clen -= offset;
763
        else
764
                clen = 0;
765
        return clen < len ? clen : len;
766
}
767
 
768
static ssize_t
769
fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
770
{
771
        unsigned long p = *ppos;
772
        struct inode *inode = file->f_dentry->d_inode;
773
        int fbidx = iminor(inode);
774
        struct fb_info *info = registered_fb[fbidx];
775
 
776
        if (!info || ! info->screen_base)
777
                return -ENODEV;
778
 
779
        if (info->fbops->fb_read)
780
                return info->fbops->fb_read(file, buf, count, ppos);
781
 
782
        if (p >= info->fix.smem_len)
783
            return 0;
784
        if (count >= info->fix.smem_len)
785
            count = info->fix.smem_len;
786
        if (count + p > info->fix.smem_len)
787
                count = info->fix.smem_len - p;
788
        if (info->fbops->fb_sync)
789
                info->fbops->fb_sync(info);
790
        if (count) {
791
            char *base_addr;
792
 
793
            base_addr = info->screen_base;
794
            count -= copy_to_user(buf, base_addr+p, count);
795
            if (!count)
796
                return -EFAULT;
797
            *ppos += count;
798
        }
799
        return count;
800
}
801
 
802
static ssize_t
803
fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
804
{
805
        unsigned long p = *ppos;
806
        struct inode *inode = file->f_dentry->d_inode;
807
        int fbidx = iminor(inode);
808
        struct fb_info *info = registered_fb[fbidx];
809
        int err;
810
 
811
        if (!info || !info->screen_base)
812
                return -ENODEV;
813
 
814
        if (info->fbops->fb_write)
815
                return info->fbops->fb_write(file, buf, count, ppos);
816
 
817
        if (p > info->fix.smem_len)
818
            return -ENOSPC;
819
        if (count >= info->fix.smem_len)
820
            count = info->fix.smem_len;
821
        err = 0;
822
        if (count + p > info->fix.smem_len) {
823
            count = info->fix.smem_len - p;
824
            err = -ENOSPC;
825
        }
826
        if (info->fbops->fb_sync)
827
                info->fbops->fb_sync(info);
828
        if (count) {
829
            char *base_addr;
830
 
831
            base_addr = info->screen_base;
832
            count -= copy_from_user(base_addr+p, buf, count);
833
            *ppos += count;
834
            err = -EFAULT;
835
        }
836
        if (count)
837
                return count;
838
        return err;
839
}
840
 
841
#ifdef CONFIG_KMOD
842
static void try_to_load(int fb)
843
{
844
        request_module("fb%d", fb);
845
}
846
#endif /* CONFIG_KMOD */
847
 
848
int
849
fb_cursor(struct fb_info *info, struct fb_cursor *sprite)
850
{
851
        struct fb_cursor cursor;
852
        int err;
853
 
854
        if (copy_from_user(&cursor, sprite, sizeof(struct fb_cursor)))
855
                return -EFAULT;
856
 
857
        if (cursor.set & FB_CUR_SETCUR)
858
                info->cursor.enable = 1;
859
 
860
        if (cursor.set & FB_CUR_SETCMAP) {
861
                err = fb_copy_cmap(&cursor.image.cmap, &sprite->image.cmap, 1);
862
                if (err)
863
                        return err;
864
        }
865
 
866
        if (cursor.set & FB_CUR_SETSHAPE) {
867
                int size = ((cursor.image.width + 7) >> 3) * cursor.image.height;              
868
                if ((cursor.image.height != info->cursor.image.height) ||
869
                    (cursor.image.width != info->cursor.image.width))
870
                        cursor.set |= FB_CUR_SETSIZE;
871
 
872
                cursor.image.data = kmalloc(size, GFP_KERNEL);
873
                if (!cursor.image.data)
874
                        return -ENOMEM;
875
 
876
                cursor.mask = kmalloc(size, GFP_KERNEL);
877
                if (!cursor.mask) {
878
                        kfree(cursor.image.data);
879
                        return -ENOMEM;
880
                }
881
 
882
                if (copy_from_user(&cursor.image.data, sprite->image.data, size) ||
883
                    copy_from_user(cursor.mask, sprite->mask, size)) {
884
                        kfree(cursor.image.data);
885
                        kfree(cursor.mask);
886
                        return -EFAULT;
887
                }
888
        }
889
        info->cursor.set = cursor.set;
890
        info->cursor.rop = cursor.rop;
891
        err = info->fbops->fb_cursor(info, &cursor);
892
        return err;
893
}
894
 
895
int
896
fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
897
{
898
        int xoffset = var->xoffset;
899
        int yoffset = var->yoffset;
900
        int err;
901
 
902
        if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display ||
903
            xoffset + info->var.xres > info->var.xres_virtual ||
904
            yoffset + info->var.yres > info->var.yres_virtual)
905
                return -EINVAL;
906
        if ((err = info->fbops->fb_pan_display(var, info)))
907
                return err;
908
        info->var.xoffset = var->xoffset;
909
        info->var.yoffset = var->yoffset;
910
        if (var->vmode & FB_VMODE_YWRAP)
911
                info->var.vmode |= FB_VMODE_YWRAP;
912
        else
913
                info->var.vmode &= ~FB_VMODE_YWRAP;
914
        return 0;
915
}
916
 
917
int
918
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
919
{
920
        int err;
921
 
922
        if (memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
923
                if (!info->fbops->fb_check_var) {
924
                        *var = info->var;
925
                        return 0;
926
                }
927
 
928
                if ((err = info->fbops->fb_check_var(var, info)))
929
                        return err;
930
 
931
                if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
932
                        info->var = *var;
933
 
934
                        if (info->fbops->fb_set_par)
935
                                info->fbops->fb_set_par(info);
936
 
937
                        fb_pan_display(info, &info->var);
938
 
939
                        fb_set_cmap(&info->cmap, 1, info);
940
                }
941
        }
942
        return 0;
943
}
944
 
945
int
946
fb_blank(struct fb_info *info, int blank)
947
{      
948
        /* ??? Variable sized stack allocation.  */
949
        u16 black[info->cmap.len];
950
        struct fb_cmap cmap;
951
 
952
        if (info->fbops->fb_blank && !info->fbops->fb_blank(blank, info))
953
                return 0;
954
        if (blank) {
955
                memset(black, 0, info->cmap.len * sizeof(u16));
956
                cmap.red = cmap.green = cmap.blue = black;
957
                cmap.transp = info->cmap.transp ? black : NULL;
958
                cmap.start = info->cmap.start;
959
                cmap.len = info->cmap.len;
960
        } else
961
                cmap = info->cmap;
962
        return fb_set_cmap(&cmap, 1, info);
963
}
964
 
472 giacomo 965
int
466 giacomo 966
fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
967
         unsigned long arg)
968
{
969
        int fbidx = iminor(inode);
970
        struct fb_info *info = registered_fb[fbidx];
971
        struct fb_ops *fb = info->fbops;
972
        struct fb_var_screeninfo var;
973
        struct fb_fix_screeninfo fix;
974
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
975
        struct fb_con2fbmap con2fb;
976
#endif
977
        struct fb_cmap cmap;
482 giacomo 978
        struct fb_fillrect rect;
466 giacomo 979
        int i;
980
 
981
        if (!fb)
982
                return -ENODEV;
983
        switch (cmd) {
984
        case FBIOGET_VSCREENINFO:
985
                return copy_to_user((void *) arg, &info->var,
986
                                    sizeof(var)) ? -EFAULT : 0;
987
        case FBIOPUT_VSCREENINFO:
988
                if (copy_from_user(&var, (void *) arg, sizeof(var)))
989
                        return -EFAULT;
990
                i = fb_set_var(info, &var);
991
                if (i) return i;
992
                if (copy_to_user((void *) arg, &var, sizeof(var)))
993
                        return -EFAULT;
482 giacomo 994
 
995
                rect.dx = 0;
996
                rect.dy = 0;
997
                rect.width = info->var.xres;
998
                rect.height = info->var.yres;
999
                rect.color = 0;
1000
                rect.rop = ROP_COPY;
1001
 
1002
                cfb_fillrect(info,&rect);
1003
 
1004
                if (info->var.bits_per_pixel >= 8) {
1005
 
1006
                        fb_prepare_logo(info);
1007
                        fb_show_logo(info);
1008
 
1009
                }
1010
 
466 giacomo 1011
                return 0;
1012
        case FBIOGET_FSCREENINFO:
1013
                return copy_to_user((void *) arg, &info->fix,
1014
                                    sizeof(fix)) ? -EFAULT : 0;
1015
        case FBIOPUTCMAP:
1016
                if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
1017
                        return -EFAULT;
1018
                return (fb_set_cmap(&cmap, 0, info));
1019
        case FBIOGETCMAP:
1020
                if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
1021
                        return -EFAULT;
1022
                return (fb_copy_cmap(&info->cmap, &cmap, 0));
1023
        case FBIOPAN_DISPLAY:
1024
                if (copy_from_user(&var, (void *) arg, sizeof(var)))
1025
                        return -EFAULT;
1026
                if ((i = fb_pan_display(info, &var)))
1027
                        return i;
1028
                if (copy_to_user((void *) arg, &var, sizeof(var)))
1029
                        return -EFAULT;
1030
                return 0;
1031
        case FBIO_CURSOR:
1032
                return (fb_cursor(info, (struct fb_cursor *) arg));
1033
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
1034
        case FBIOGET_CON2FBMAP:
1035
                if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
1036
                        return -EFAULT;
1037
                if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1038
                    return -EINVAL;
1039
                con2fb.framebuffer = con2fb_map[con2fb.console-1];
1040
                return copy_to_user((void *)arg, &con2fb,
1041
                                    sizeof(con2fb)) ? -EFAULT : 0;
1042
        case FBIOPUT_CON2FBMAP:
1043
                if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
1044
                        return - EFAULT;
1045
                if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
1046
                    return -EINVAL;
1047
                if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
1048
                    return -EINVAL;
1049
#ifdef CONFIG_KMOD
1050
                if (!registered_fb[con2fb.framebuffer])
1051
                    try_to_load(con2fb.framebuffer);
1052
#endif /* CONFIG_KMOD */
1053
                if (!registered_fb[con2fb.framebuffer])
1054
                    return -EINVAL;
1055
                if (con2fb.console != 0)
1056
                        set_con2fb_map(con2fb.console-1, con2fb.framebuffer);
1057
                else
1058
                        fb_console_init();             
1059
                return 0;
1060
#endif  /* CONFIG_FRAMEBUFFER_CONSOLE */
1061
        case FBIOBLANK:
483 giacomo 1062
                return fb_blank(info, arg);            
466 giacomo 1063
        default:
1064
                if (fb->fb_ioctl == NULL)
1065
                        return -EINVAL;
1066
                return fb->fb_ioctl(inode, file, cmd, arg, info);
1067
        }
1068
}
1069
 
1070
static int
1071
fb_mmap(struct file *file, struct vm_area_struct * vma)
1072
{
1073
        int fbidx = iminor(file->f_dentry->d_inode);
1074
        struct fb_info *info = registered_fb[fbidx];
1075
        struct fb_ops *fb = info->fbops;
1076
        unsigned long off;
1077
#if !defined(__sparc__) || defined(__sparc_v9__)
1078
        unsigned long start;
1079
        u32 len;
1080
#endif
1081
 
1082
        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1083
                return -EINVAL;
1084
        off = vma->vm_pgoff << PAGE_SHIFT;
1085
        if (!fb)
1086
                return -ENODEV;
1087
        if (fb->fb_mmap) {
1088
                int res;
1089
                lock_kernel();
1090
                res = fb->fb_mmap(info, file, vma);
1091
                unlock_kernel();
1092
                return res;
1093
        }
1094
 
1095
#if defined(__sparc__) && !defined(__sparc_v9__)
1096
        /* Should never get here, all fb drivers should have their own
1097
           mmap routines */
1098
        return -EINVAL;
1099
#else
1100
        /* !sparc32... */
1101
        lock_kernel();
1102
 
1103
        /* frame buffer memory */
1104
        start = info->fix.smem_start;
1105
        len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
1106
        if (off >= len) {
1107
                /* memory mapped io */
1108
                off -= len;
1109
                if (info->var.accel_flags) {
1110
                        unlock_kernel();
1111
                        return -EINVAL;
1112
                }
1113
                start = info->fix.mmio_start;
1114
                len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
1115
        }
1116
        unlock_kernel();
1117
        start &= PAGE_MASK;
1118
        if ((vma->vm_end - vma->vm_start + off) > len)
1119
                return -EINVAL;
1120
        off += start;
1121
        vma->vm_pgoff = off >> PAGE_SHIFT;
1122
        /* This is an IO map - tell maydump to skip this VMA */
1123
        vma->vm_flags |= VM_IO;
1124
#if defined(__sparc_v9__)
1125
        vma->vm_flags |= (VM_SHM | VM_LOCKED);
1126
        if (io_remap_page_range(vma, vma->vm_start, off,
1127
                                vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
1128
                return -EAGAIN;
1129
#else
1130
#if defined(__mc68000__)
1131
#if defined(CONFIG_SUN3)
1132
        pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
1133
#elif defined(CONFIG_MMU)
1134
        if (CPU_IS_020_OR_030)
1135
                pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
1136
        if (CPU_IS_040_OR_060) {
1137
                pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
1138
                /* Use no-cache mode, serialized */
1139
                pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
1140
        }
1141
#endif
1142
#elif defined(__powerpc__)
1143
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
1144
#elif defined(__alpha__)
1145
        /* Caching is off in the I/O space quadrant by design.  */
1146
#elif defined(__i386__) || defined(__x86_64__)
468 giacomo 1147
        //if (boot_cpu_data.x86 > 3)
1148
        //      pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
466 giacomo 1149
#elif defined(__mips__)
1150
        pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
1151
        pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
1152
#elif defined(__sh__)
1153
        pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
1154
#elif defined(__hppa__)
1155
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
1156
#elif defined(__ia64__) || defined(__arm__)
1157
        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1158
#else
1159
#warning What do we have to do here??
1160
#endif
1161
        if (io_remap_page_range(vma, vma->vm_start, off,
1162
                             vma->vm_end - vma->vm_start, vma->vm_page_prot))
1163
                return -EAGAIN;
1164
#endif /* !__sparc_v9__ */
1165
        return 0;
1166
#endif /* !sparc32 */
1167
}
1168
 
470 giacomo 1169
static int
466 giacomo 1170
fb_open(struct inode *inode, struct file *file)
1171
{
1172
        int fbidx = iminor(inode);
1173
        struct fb_info *info;
477 giacomo 1174
        struct fb_fillrect rect;
476 giacomo 1175
        int res = 0;
466 giacomo 1176
 
1177
        if (fbidx >= FB_MAX)
1178
                return -ENODEV;
1179
#ifdef CONFIG_KMOD
1180
        if (!(info = registered_fb[fbidx]))
1181
                try_to_load(fbidx);
1182
#endif /* CONFIG_KMOD */
1183
        if (!(info = registered_fb[fbidx]))
1184
                return -ENODEV;
1185
        if (!try_module_get(info->fbops->owner))
1186
                return -ENODEV;
1187
        if (info->fbops->fb_open) {
1188
                res = info->fbops->fb_open(info,1);
1189
                if (res)
1190
                        module_put(info->fbops->owner);
1191
        }
475 giacomo 1192
 
476 giacomo 1193
        info->fbops->fb_set_par(info);
1194
        fb_pan_display(info, &info->var);
1195
 
477 giacomo 1196
        rect.dx = 0;
1197
        rect.dy = 0;
1198
        rect.width = info->var.xres;
1199
        rect.height = info->var.yres;
1200
        rect.color = 0;
1201
        rect.rop = ROP_COPY;
1202
 
1203
        cfb_fillrect(info,&rect);
1204
 
476 giacomo 1205
        if (info->var.bits_per_pixel >= 8) {   
1206
 
1207
          fb_prepare_logo(info);
1208
          fb_show_logo(info);
1209
 
1210
        }
475 giacomo 1211
 
466 giacomo 1212
        return res;
1213
}
1214
 
470 giacomo 1215
static int
466 giacomo 1216
fb_release(struct inode *inode, struct file *file)
1217
{
1218
        int fbidx = iminor(inode);
1219
        struct fb_info *info;
1220
 
1221
        lock_kernel();
1222
        info = registered_fb[fbidx];
1223
        if (info->fbops->fb_release)
1224
                info->fbops->fb_release(info,1);
1225
        module_put(info->fbops->owner);
1226
        unlock_kernel();
475 giacomo 1227
 
466 giacomo 1228
        return 0;
1229
}
1230
 
1231
static struct file_operations fb_fops = {
1232
        .owner =        THIS_MODULE,
1233
        .read =         fb_read,
1234
        .write =        fb_write,
1235
        .ioctl =        fb_ioctl,
1236
        .mmap =         fb_mmap,
1237
        .open =         fb_open,
1238
        .release =      fb_release,
1239
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
1240
        .get_unmapped_area = get_fb_unmapped_area,
1241
#endif
1242
};
1243
 
1244
/**
1245
 *      register_framebuffer - registers a frame buffer device
1246
 *      @fb_info: frame buffer info structure
1247
 *
1248
 *      Registers a frame buffer device @fb_info.
1249
 *
1250
 *      Returns negative errno on error, or zero for success.
1251
 *
1252
 */
1253
 
1254
int
1255
register_framebuffer(struct fb_info *fb_info)
1256
{
1257
        int i;
1258
 
1259
        if (num_registered_fb == FB_MAX)
1260
                return -ENXIO;
1261
        num_registered_fb++;
1262
        for (i = 0 ; i < FB_MAX; i++)
1263
                if (!registered_fb[i])
1264
                        break;
1265
        fb_info->node = i;
1266
 
1267
        if (fb_info->pixmap.addr == NULL) {
1268
                fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
1269
                if (fb_info->pixmap.addr) {
1270
                        fb_info->pixmap.size = FBPIXMAPSIZE;
1271
                        fb_info->pixmap.buf_align = 1;
1272
                        fb_info->pixmap.scan_align = 1;
1273
                        fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
1274
                }
1275
        }      
1276
        fb_info->pixmap.offset = 0;
1277
        if (fb_info->pixmap.outbuf == NULL)
1278
                fb_info->pixmap.outbuf = sys_outbuf;
1279
        if (fb_info->pixmap.inbuf == NULL)
1280
                fb_info->pixmap.inbuf = sys_inbuf;
1281
        spin_lock_init(&fb_info->pixmap.lock);
1282
 
1283
        registered_fb[i] = fb_info;
1284
 
1285
        devfs_mk_cdev(MKDEV(FB_MAJOR, i),
1286
                        S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
1287
        return 0;
1288
}
1289
 
1290
 
1291
/**
1292
 *      unregister_framebuffer - releases a frame buffer device
1293
 *      @fb_info: frame buffer info structure
1294
 *
1295
 *      Unregisters a frame buffer device @fb_info.
1296
 *
1297
 *      Returns negative errno on error, or zero for success.
1298
 *
1299
 */
1300
 
1301
int
1302
unregister_framebuffer(struct fb_info *fb_info)
1303
{
1304
        int i;
1305
 
1306
        i = fb_info->node;
1307
        if (!registered_fb[i])
1308
                return -EINVAL;
1309
        devfs_remove("fb/%d", i);
1310
 
1311
        if (fb_info->pixmap.addr)
1312
                kfree(fb_info->pixmap.addr);
1313
        registered_fb[i]=NULL;
1314
        num_registered_fb--;
1315
        return 0;
1316
}
1317
 
1318
 
1319
/**
1320
 *      fbmem_init - init frame buffer subsystem
1321
 *
1322
 *      Initialize the frame buffer subsystem.
1323
 *
1324
 *      NOTE: This function is _only_ to be called by drivers/char/mem.c.
1325
 *
1326
 */
1327
 
1328
void __init
1329
fbmem_init(void)
1330
{
1331
        int i;
1332
 
1333
        create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL);
1334
 
1335
        devfs_mk_dir("fb");
1336
        if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
1337
                printk("unable to get major %d for fb devs\n", FB_MAJOR);
1338
 
1339
#ifdef CONFIG_FB_OF
1340
        if (ofonly) {
1341
                offb_init();
1342
                return;
1343
        }
1344
#endif
1345
 
1346
        /*
1347
         *  Probe for all builtin frame buffer devices
1348
         */
1349
        for (i = 0; i < num_pref_init_funcs; i++)
1350
                pref_init_funcs[i]();
1351
 
1352
        for (i = 0; i < NUM_FB_DRIVERS; i++)
1353
                if (fb_drivers[i].init)
1354
                        fb_drivers[i].init();
1355
}
1356
 
469 giacomo 1357
extern int linuxcomp_setfd(struct inode *i, int i_rdev);
466 giacomo 1358
 
469 giacomo 1359
/* Shark Inode emulation */
1360
int fb_open_inode(int num) {
470 giacomo 1361
 
1362
  struct inode *i;
1363
 
1364
  i = (struct inode *)kmalloc(sizeof(struct inode),GFP_KERNEL);
1365
 
1366
  linuxcomp_setfd(i,num);
1367
 
472 giacomo 1368
  if (fb_open(i,NULL)) {
1369
    kfree(i);
1370
    return -1;
1371
  }
469 giacomo 1372
 
475 giacomo 1373
  kfree(i);                                                                                                            
470 giacomo 1374
  return 0;
1375
 
1376
}
1377
 
1378
/* Shark Inode emulation */
1379
int fb_close_inode(int num) {
1380
 
469 giacomo 1381
  struct inode *i;
1382
 
1383
  i = (struct inode *)kmalloc(sizeof(struct inode),GFP_KERNEL);
1384
 
1385
  linuxcomp_setfd(i,num);
1386
 
472 giacomo 1387
  if(fb_release(i,NULL)) {
1388
    kfree(i);
1389
    return -1;
1390
  }
469 giacomo 1391
 
470 giacomo 1392
  kfree(i);
1393
 
469 giacomo 1394
  return 0;
1395
 
1396
}
1397
 
483 giacomo 1398
int fb_set_mode_inode(int num, unsigned char *modeopt) {
472 giacomo 1399
 
1400
  struct inode *i;
1401
  struct fb_var_screeninfo var;
483 giacomo 1402
  struct fb_info *info = registered_fb[num];
472 giacomo 1403
 
1404
  i = (struct inode *)kmalloc(sizeof(struct inode),GFP_KERNEL);
1405
 
1406
  linuxcomp_setfd(i,num);
1407
 
1408
  if (fb_ioctl(i, NULL, FBIOGET_VSCREENINFO, (unsigned long)&var)) {
1409
    kfree(i);
1410
    return -1;
483 giacomo 1411
  }
472 giacomo 1412
 
483 giacomo 1413
  fb_find_mode(&var,info,modeopt,NULL,0,NULL,0);
1414
 
472 giacomo 1415
  var.xoffset = 0;
1416
  var.yoffset = 0;
483 giacomo 1417
  var.xres_virtual = var.xres;
1418
  var.yres_virtual = var.yres;
472 giacomo 1419
 
1420
  if (fb_ioctl(i, NULL, FBIOPUT_VSCREENINFO, (unsigned long)&var)) {
1421
    kfree(i);
1422
    return -1;
1423
  }
1424
 
1425
  kfree(i);
1426
 
1427
  return 0;
1428
 
1429
}
1430
 
466 giacomo 1431
/**
1432
 *      video_setup - process command line options
1433
 *      @options: string of options
1434
 *
1435
 *      Process command line options for frame buffer subsystem.
1436
 *
1437
 *      NOTE: This function is a __setup and __init function.
1438
 *
1439
 *      Returns zero.
1440
 *
1441
 */
1442
 
1443
int __init video_setup(char *options)
1444
{
1445
        int i, j;
1446
 
1447
        if (!options || !*options)
1448
                return 0;
1449
 
1450
#ifdef CONFIG_FB_OF
1451
        if (!strcmp(options, "ofonly")) {
1452
                ofonly = 1;
1453
                return 0;
1454
        }
1455
#endif
1456
 
1457
        if (num_pref_init_funcs == FB_MAX)
1458
                return 0;
1459
 
1460
        for (i = 0; i < NUM_FB_DRIVERS; i++) {
1461
                j = strlen(fb_drivers[i].name);
1462
                if (!strncmp(options, fb_drivers[i].name, j) &&
1463
                        options[j] == ':') {
1464
                        if (!strcmp(options+j+1, "off"))
1465
                                fb_drivers[i].init = NULL;
1466
                        else {
1467
                                if (fb_drivers[i].init) {
1468
                                        pref_init_funcs[num_pref_init_funcs++] =
1469
                                                fb_drivers[i].init;
1470
                                        fb_drivers[i].init = NULL;
1471
                                }
1472
                                if (fb_drivers[i].setup)
1473
                                        fb_drivers[i].setup(options+j+1);
1474
                        }
1475
                        return 0;
1476
                }
1477
        }
1478
 
1479
        /*
1480
         * If we get here no fb was specified.
1481
         * We consider the argument to be a global video mode option.
1482
         */
468 giacomo 1483
        //global_mode_option = options;
466 giacomo 1484
        return 0;
1485
}
1486
 
1487
__setup("video=", video_setup);
1488
 
1489
    /*
1490
     *  Visible symbols for modules
1491
     */
1492
 
1493
EXPORT_SYMBOL(register_framebuffer);
1494
EXPORT_SYMBOL(unregister_framebuffer);
1495
EXPORT_SYMBOL(num_registered_fb);
1496
EXPORT_SYMBOL(registered_fb);
1497
EXPORT_SYMBOL(fb_prepare_logo);
1498
EXPORT_SYMBOL(fb_show_logo);
1499
EXPORT_SYMBOL(fb_set_var);
1500
EXPORT_SYMBOL(fb_blank);
1501
EXPORT_SYMBOL(fb_pan_display);
1502
EXPORT_SYMBOL(fb_get_buffer_offset);
1503
EXPORT_SYMBOL(move_buf_unaligned);
1504
EXPORT_SYMBOL(move_buf_aligned);
1505
 
1506
MODULE_LICENSE("GPL");