Subversion Repositories shark

Rev

Rev 470 | Rev 475 | 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;
978
        int i;
979
 
980
        if (!fb)
981
                return -ENODEV;
982
        switch (cmd) {
983
        case FBIOGET_VSCREENINFO:
984
                return copy_to_user((void *) arg, &info->var,
985
                                    sizeof(var)) ? -EFAULT : 0;
986
        case FBIOPUT_VSCREENINFO:
987
                if (copy_from_user(&var, (void *) arg, sizeof(var)))
988
                        return -EFAULT;
989
                i = fb_set_var(info, &var);
990
                if (i) return i;
991
                if (copy_to_user((void *) arg, &var, sizeof(var)))
992
                        return -EFAULT;
993
                return 0;
994
        case FBIOGET_FSCREENINFO:
995
                return copy_to_user((void *) arg, &info->fix,
996
                                    sizeof(fix)) ? -EFAULT : 0;
997
        case FBIOPUTCMAP:
998
                if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
999
                        return -EFAULT;
1000
                return (fb_set_cmap(&cmap, 0, info));
1001
        case FBIOGETCMAP:
1002
                if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
1003
                        return -EFAULT;
1004
                return (fb_copy_cmap(&info->cmap, &cmap, 0));
1005
        case FBIOPAN_DISPLAY:
1006
                if (copy_from_user(&var, (void *) arg, sizeof(var)))
1007
                        return -EFAULT;
1008
                if ((i = fb_pan_display(info, &var)))
1009
                        return i;
1010
                if (copy_to_user((void *) arg, &var, sizeof(var)))
1011
                        return -EFAULT;
1012
                return 0;
1013
        case FBIO_CURSOR:
1014
                return (fb_cursor(info, (struct fb_cursor *) arg));
1015
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
1016
        case FBIOGET_CON2FBMAP:
1017
                if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
1018
                        return -EFAULT;
1019
                if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
1020
                    return -EINVAL;
1021
                con2fb.framebuffer = con2fb_map[con2fb.console-1];
1022
                return copy_to_user((void *)arg, &con2fb,
1023
                                    sizeof(con2fb)) ? -EFAULT : 0;
1024
        case FBIOPUT_CON2FBMAP:
1025
                if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
1026
                        return - EFAULT;
1027
                if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
1028
                    return -EINVAL;
1029
                if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
1030
                    return -EINVAL;
1031
#ifdef CONFIG_KMOD
1032
                if (!registered_fb[con2fb.framebuffer])
1033
                    try_to_load(con2fb.framebuffer);
1034
#endif /* CONFIG_KMOD */
1035
                if (!registered_fb[con2fb.framebuffer])
1036
                    return -EINVAL;
1037
                if (con2fb.console != 0)
1038
                        set_con2fb_map(con2fb.console-1, con2fb.framebuffer);
1039
                else
1040
                        fb_console_init();             
1041
                return 0;
1042
#endif  /* CONFIG_FRAMEBUFFER_CONSOLE */
1043
        case FBIOBLANK:
1044
                return fb_blank(info, arg);
1045
        default:
1046
                if (fb->fb_ioctl == NULL)
1047
                        return -EINVAL;
1048
                return fb->fb_ioctl(inode, file, cmd, arg, info);
1049
        }
1050
}
1051
 
1052
static int
1053
fb_mmap(struct file *file, struct vm_area_struct * vma)
1054
{
1055
        int fbidx = iminor(file->f_dentry->d_inode);
1056
        struct fb_info *info = registered_fb[fbidx];
1057
        struct fb_ops *fb = info->fbops;
1058
        unsigned long off;
1059
#if !defined(__sparc__) || defined(__sparc_v9__)
1060
        unsigned long start;
1061
        u32 len;
1062
#endif
1063
 
1064
        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1065
                return -EINVAL;
1066
        off = vma->vm_pgoff << PAGE_SHIFT;
1067
        if (!fb)
1068
                return -ENODEV;
1069
        if (fb->fb_mmap) {
1070
                int res;
1071
                lock_kernel();
1072
                res = fb->fb_mmap(info, file, vma);
1073
                unlock_kernel();
1074
                return res;
1075
        }
1076
 
1077
#if defined(__sparc__) && !defined(__sparc_v9__)
1078
        /* Should never get here, all fb drivers should have their own
1079
           mmap routines */
1080
        return -EINVAL;
1081
#else
1082
        /* !sparc32... */
1083
        lock_kernel();
1084
 
1085
        /* frame buffer memory */
1086
        start = info->fix.smem_start;
1087
        len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
1088
        if (off >= len) {
1089
                /* memory mapped io */
1090
                off -= len;
1091
                if (info->var.accel_flags) {
1092
                        unlock_kernel();
1093
                        return -EINVAL;
1094
                }
1095
                start = info->fix.mmio_start;
1096
                len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
1097
        }
1098
        unlock_kernel();
1099
        start &= PAGE_MASK;
1100
        if ((vma->vm_end - vma->vm_start + off) > len)
1101
                return -EINVAL;
1102
        off += start;
1103
        vma->vm_pgoff = off >> PAGE_SHIFT;
1104
        /* This is an IO map - tell maydump to skip this VMA */
1105
        vma->vm_flags |= VM_IO;
1106
#if defined(__sparc_v9__)
1107
        vma->vm_flags |= (VM_SHM | VM_LOCKED);
1108
        if (io_remap_page_range(vma, vma->vm_start, off,
1109
                                vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
1110
                return -EAGAIN;
1111
#else
1112
#if defined(__mc68000__)
1113
#if defined(CONFIG_SUN3)
1114
        pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
1115
#elif defined(CONFIG_MMU)
1116
        if (CPU_IS_020_OR_030)
1117
                pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
1118
        if (CPU_IS_040_OR_060) {
1119
                pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
1120
                /* Use no-cache mode, serialized */
1121
                pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
1122
        }
1123
#endif
1124
#elif defined(__powerpc__)
1125
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
1126
#elif defined(__alpha__)
1127
        /* Caching is off in the I/O space quadrant by design.  */
1128
#elif defined(__i386__) || defined(__x86_64__)
468 giacomo 1129
        //if (boot_cpu_data.x86 > 3)
1130
        //      pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
466 giacomo 1131
#elif defined(__mips__)
1132
        pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
1133
        pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
1134
#elif defined(__sh__)
1135
        pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
1136
#elif defined(__hppa__)
1137
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
1138
#elif defined(__ia64__) || defined(__arm__)
1139
        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1140
#else
1141
#warning What do we have to do here??
1142
#endif
1143
        if (io_remap_page_range(vma, vma->vm_start, off,
1144
                             vma->vm_end - vma->vm_start, vma->vm_page_prot))
1145
                return -EAGAIN;
1146
#endif /* !__sparc_v9__ */
1147
        return 0;
1148
#endif /* !sparc32 */
1149
}
1150
 
470 giacomo 1151
static int
466 giacomo 1152
fb_open(struct inode *inode, struct file *file)
1153
{
1154
        int fbidx = iminor(inode);
1155
        struct fb_info *info;
1156
        int res = 0;
1157
 
1158
        if (fbidx >= FB_MAX)
1159
                return -ENODEV;
1160
#ifdef CONFIG_KMOD
1161
        if (!(info = registered_fb[fbidx]))
1162
                try_to_load(fbidx);
1163
#endif /* CONFIG_KMOD */
1164
        if (!(info = registered_fb[fbidx]))
1165
                return -ENODEV;
1166
        if (!try_module_get(info->fbops->owner))
1167
                return -ENODEV;
1168
        if (info->fbops->fb_open) {
1169
                res = info->fbops->fb_open(info,1);
1170
                if (res)
1171
                        module_put(info->fbops->owner);
1172
        }
1173
        return res;
1174
}
1175
 
470 giacomo 1176
static int
466 giacomo 1177
fb_release(struct inode *inode, struct file *file)
1178
{
1179
        int fbidx = iminor(inode);
1180
        struct fb_info *info;
1181
 
1182
        lock_kernel();
1183
        info = registered_fb[fbidx];
1184
        if (info->fbops->fb_release)
1185
                info->fbops->fb_release(info,1);
1186
        module_put(info->fbops->owner);
1187
        unlock_kernel();
1188
        return 0;
1189
}
1190
 
1191
static struct file_operations fb_fops = {
1192
        .owner =        THIS_MODULE,
1193
        .read =         fb_read,
1194
        .write =        fb_write,
1195
        .ioctl =        fb_ioctl,
1196
        .mmap =         fb_mmap,
1197
        .open =         fb_open,
1198
        .release =      fb_release,
1199
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
1200
        .get_unmapped_area = get_fb_unmapped_area,
1201
#endif
1202
};
1203
 
1204
/**
1205
 *      register_framebuffer - registers a frame buffer device
1206
 *      @fb_info: frame buffer info structure
1207
 *
1208
 *      Registers a frame buffer device @fb_info.
1209
 *
1210
 *      Returns negative errno on error, or zero for success.
1211
 *
1212
 */
1213
 
1214
int
1215
register_framebuffer(struct fb_info *fb_info)
1216
{
1217
        int i;
1218
 
1219
        if (num_registered_fb == FB_MAX)
1220
                return -ENXIO;
1221
        num_registered_fb++;
1222
        for (i = 0 ; i < FB_MAX; i++)
1223
                if (!registered_fb[i])
1224
                        break;
1225
        fb_info->node = i;
1226
 
1227
        if (fb_info->pixmap.addr == NULL) {
1228
                fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
1229
                if (fb_info->pixmap.addr) {
1230
                        fb_info->pixmap.size = FBPIXMAPSIZE;
1231
                        fb_info->pixmap.buf_align = 1;
1232
                        fb_info->pixmap.scan_align = 1;
1233
                        fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
1234
                }
1235
        }      
1236
        fb_info->pixmap.offset = 0;
1237
        if (fb_info->pixmap.outbuf == NULL)
1238
                fb_info->pixmap.outbuf = sys_outbuf;
1239
        if (fb_info->pixmap.inbuf == NULL)
1240
                fb_info->pixmap.inbuf = sys_inbuf;
1241
        spin_lock_init(&fb_info->pixmap.lock);
1242
 
1243
        registered_fb[i] = fb_info;
1244
 
1245
        devfs_mk_cdev(MKDEV(FB_MAJOR, i),
1246
                        S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
1247
        return 0;
1248
}
1249
 
1250
 
1251
/**
1252
 *      unregister_framebuffer - releases a frame buffer device
1253
 *      @fb_info: frame buffer info structure
1254
 *
1255
 *      Unregisters a frame buffer device @fb_info.
1256
 *
1257
 *      Returns negative errno on error, or zero for success.
1258
 *
1259
 */
1260
 
1261
int
1262
unregister_framebuffer(struct fb_info *fb_info)
1263
{
1264
        int i;
1265
 
1266
        i = fb_info->node;
1267
        if (!registered_fb[i])
1268
                return -EINVAL;
1269
        devfs_remove("fb/%d", i);
1270
 
1271
        if (fb_info->pixmap.addr)
1272
                kfree(fb_info->pixmap.addr);
1273
        registered_fb[i]=NULL;
1274
        num_registered_fb--;
1275
        return 0;
1276
}
1277
 
1278
 
1279
/**
1280
 *      fbmem_init - init frame buffer subsystem
1281
 *
1282
 *      Initialize the frame buffer subsystem.
1283
 *
1284
 *      NOTE: This function is _only_ to be called by drivers/char/mem.c.
1285
 *
1286
 */
1287
 
1288
void __init
1289
fbmem_init(void)
1290
{
1291
        int i;
1292
 
1293
        create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL);
1294
 
1295
        devfs_mk_dir("fb");
1296
        if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
1297
                printk("unable to get major %d for fb devs\n", FB_MAJOR);
1298
 
1299
#ifdef CONFIG_FB_OF
1300
        if (ofonly) {
1301
                offb_init();
1302
                return;
1303
        }
1304
#endif
1305
 
1306
        /*
1307
         *  Probe for all builtin frame buffer devices
1308
         */
1309
        for (i = 0; i < num_pref_init_funcs; i++)
1310
                pref_init_funcs[i]();
1311
 
1312
        for (i = 0; i < NUM_FB_DRIVERS; i++)
1313
                if (fb_drivers[i].init)
1314
                        fb_drivers[i].init();
1315
}
1316
 
469 giacomo 1317
extern int linuxcomp_setfd(struct inode *i, int i_rdev);
466 giacomo 1318
 
469 giacomo 1319
/* Shark Inode emulation */
1320
int fb_open_inode(int num) {
470 giacomo 1321
 
1322
  struct inode *i;
1323
 
1324
  i = (struct inode *)kmalloc(sizeof(struct inode),GFP_KERNEL);
1325
 
1326
  linuxcomp_setfd(i,num);
1327
 
472 giacomo 1328
  if (fb_open(i,NULL)) {
1329
    kfree(i);
1330
    return -1;
1331
  }
469 giacomo 1332
 
470 giacomo 1333
  kfree(i);
1334
 
1335
  return 0;
1336
 
1337
}
1338
 
1339
/* Shark Inode emulation */
1340
int fb_close_inode(int num) {
1341
 
469 giacomo 1342
  struct inode *i;
1343
 
1344
  i = (struct inode *)kmalloc(sizeof(struct inode),GFP_KERNEL);
1345
 
1346
  linuxcomp_setfd(i,num);
1347
 
472 giacomo 1348
  if(fb_release(i,NULL)) {
1349
    kfree(i);
1350
    return -1;
1351
  }
469 giacomo 1352
 
470 giacomo 1353
  kfree(i);
1354
 
469 giacomo 1355
  return 0;
1356
 
1357
}
1358
 
472 giacomo 1359
int fb_set_mode_inode(int num, int wx, int wy, int bpp) {
1360
 
1361
  struct inode *i;
1362
  struct fb_var_screeninfo var;
1363
 
1364
  i = (struct inode *)kmalloc(sizeof(struct inode),GFP_KERNEL);
1365
 
1366
  linuxcomp_setfd(i,num);
1367
 
1368
  if (fb_ioctl(i, NULL, FBIOGET_VSCREENINFO, (unsigned long)&var)) {
1369
    kfree(i);
1370
    return -1;
1371
  }
1372
 
1373
  var.xres = wx;
1374
  var.yres = wy;
1375
  var.xres_virtual = wx;
1376
  var.yres_virtual = wy;
1377
  var.xoffset = 0;
1378
  var.yoffset = 0;
1379
  var.bits_per_pixel = bpp;
1380
 
1381
  if (fb_ioctl(i, NULL, FBIOPUT_VSCREENINFO, (unsigned long)&var)) {
1382
    kfree(i);
1383
    return -1;
1384
  }
1385
 
1386
  kfree(i);
1387
 
1388
  return 0;
1389
 
1390
}
1391
 
466 giacomo 1392
/**
1393
 *      video_setup - process command line options
1394
 *      @options: string of options
1395
 *
1396
 *      Process command line options for frame buffer subsystem.
1397
 *
1398
 *      NOTE: This function is a __setup and __init function.
1399
 *
1400
 *      Returns zero.
1401
 *
1402
 */
1403
 
1404
int __init video_setup(char *options)
1405
{
1406
        int i, j;
1407
 
1408
        if (!options || !*options)
1409
                return 0;
1410
 
1411
#ifdef CONFIG_FB_OF
1412
        if (!strcmp(options, "ofonly")) {
1413
                ofonly = 1;
1414
                return 0;
1415
        }
1416
#endif
1417
 
1418
        if (num_pref_init_funcs == FB_MAX)
1419
                return 0;
1420
 
1421
        for (i = 0; i < NUM_FB_DRIVERS; i++) {
1422
                j = strlen(fb_drivers[i].name);
1423
                if (!strncmp(options, fb_drivers[i].name, j) &&
1424
                        options[j] == ':') {
1425
                        if (!strcmp(options+j+1, "off"))
1426
                                fb_drivers[i].init = NULL;
1427
                        else {
1428
                                if (fb_drivers[i].init) {
1429
                                        pref_init_funcs[num_pref_init_funcs++] =
1430
                                                fb_drivers[i].init;
1431
                                        fb_drivers[i].init = NULL;
1432
                                }
1433
                                if (fb_drivers[i].setup)
1434
                                        fb_drivers[i].setup(options+j+1);
1435
                        }
1436
                        return 0;
1437
                }
1438
        }
1439
 
1440
        /*
1441
         * If we get here no fb was specified.
1442
         * We consider the argument to be a global video mode option.
1443
         */
468 giacomo 1444
        //global_mode_option = options;
466 giacomo 1445
        return 0;
1446
}
1447
 
1448
__setup("video=", video_setup);
1449
 
1450
    /*
1451
     *  Visible symbols for modules
1452
     */
1453
 
1454
EXPORT_SYMBOL(register_framebuffer);
1455
EXPORT_SYMBOL(unregister_framebuffer);
1456
EXPORT_SYMBOL(num_registered_fb);
1457
EXPORT_SYMBOL(registered_fb);
1458
EXPORT_SYMBOL(fb_prepare_logo);
1459
EXPORT_SYMBOL(fb_show_logo);
1460
EXPORT_SYMBOL(fb_set_var);
1461
EXPORT_SYMBOL(fb_blank);
1462
EXPORT_SYMBOL(fb_pan_display);
1463
EXPORT_SYMBOL(fb_get_buffer_offset);
1464
EXPORT_SYMBOL(move_buf_unaligned);
1465
EXPORT_SYMBOL(move_buf_aligned);
1466
 
1467
MODULE_LICENSE("GPL");