Remove obsolete #include <linux/config.h>
[linux-flexiantxendom0-3.2.10.git] / drivers / video / sun3fb.c
1 /*
2  *  linux/drivers/video/sun3fb.c -- Frame buffer driver for Sun3
3  *
4  * (C) 1998 Thomas Bogendoerfer
5  *
6  * This driver is bases on sbusfb.c, which is
7  *
8  *      Copyright (C) 1998 Jakub Jelinek
9  *
10  *  This driver is partly based on the Open Firmware console driver
11  *
12  *      Copyright (C) 1997 Geert Uytterhoeven
13  *
14  *  and SPARC console subsystem
15  *
16  *      Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com)
17  *      Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
18  *      Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
19  *      Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
20  *      Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
21  *      Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
22  *
23  *  This file is subject to the terms and conditions of the GNU General Public
24  *  License. See the file COPYING in the main directory of this archive for
25  *  more details.
26  */
27
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/errno.h>
31 #include <linux/string.h>
32 #include <linux/mm.h>
33 #include <linux/tty.h>
34 #include <linux/slab.h>
35 #include <linux/vmalloc.h>
36 #include <linux/delay.h>
37 #include <linux/interrupt.h>
38 #include <linux/fb.h>
39 #include <linux/selection.h>
40 #include <linux/init.h>
41 #include <linux/console.h>
42 #include <linux/kd.h>
43 #include <linux/vt_kern.h>
44
45 #include <asm/uaccess.h>
46 #include <asm/pgtable.h>        /* io_remap_page_range() */
47
48 #ifdef CONFIG_SUN3
49 #include <asm/oplib.h>
50 #include <asm/machines.h>
51 #include <asm/idprom.h>
52
53 #define CGFOUR_OBMEM_ADDR 0x1f300000
54 #define BWTWO_OBMEM_ADDR 0x1f000000
55 #define BWTWO_OBMEM50_ADDR 0x00100000
56
57 #endif
58 #ifdef CONFIG_SUN3X
59 #include <asm/sun3x.h>
60 #endif
61 #include <video/sbusfb.h>
62
63 #define DEFAULT_CURSOR_BLINK_RATE       (2*HZ/5)
64
65 #define CURSOR_SHAPE                    1
66 #define CURSOR_BLINK                    2
67
68 #define mymemset(x,y) memset(x,0,y)
69
70     /*
71      *  Interface used by the world
72      */
73
74 int sun3fb_init(void);
75 void sun3fb_setup(char *options);
76
77 static char fontname[40] __initdata = { 0 };
78 static int curblink __initdata = 1;
79
80 static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
81                         struct fb_info *info);
82 static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
83                         struct fb_info *info);
84 static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
85                         struct fb_info *info);
86 static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
87                         struct fb_info *info);
88 static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
89                         struct fb_info *info);
90 static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
91                             u_int transp, struct fb_info *info);
92 static int sun3fb_blank(int blank, struct fb_info *info);
93 static void sun3fb_cursor(struct display *p, int mode, int x, int y);
94 static void sun3fb_clear_margin(struct display *p, int s);
95
96     /*
97      *  Interface to the low level console driver
98      */
99
100 static int sun3fbcon_switch(int con, struct fb_info *info);
101 static int sun3fbcon_updatevar(int con, struct fb_info *info);
102
103     /*
104      *  Internal routines
105      */
106
107 static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
108                             u_int *transp, struct fb_info *info);
109
110 static struct fb_ops sun3fb_ops = {
111         .owner =        THIS_MODULE,
112         .fb_get_fix =   sun3fb_get_fix,
113         .fb_get_var =   sun3fb_get_var,
114         .fb_set_var =   sun3fb_set_var,
115         .fb_get_cmap =  sun3fb_get_cmap,
116         .fb_set_cmap =  sun3fb_set_cmap,
117         .fb_setcolreg = sun3fb_setcolreg,
118         .fb_blank =     sun3fb_blank,
119 };
120
121 static void sun3fb_clear_margin(struct display *p, int s)
122 {
123         struct fb_info_sbusfb *fb = sbusfbinfod(p);
124         
125         return;
126
127         if (fb->switch_from_graph)
128                 (*fb->switch_from_graph)(fb);
129         if (fb->fill) {
130                 unsigned short rects [16];
131
132                 rects [0] = 0;
133                 rects [1] = 0;
134                 rects [2] = fb->var.xres_virtual;
135                 rects [3] = fb->y_margin;
136                 rects [4] = 0;
137                 rects [5] = fb->y_margin;
138                 rects [6] = fb->x_margin;
139                 rects [7] = fb->var.yres_virtual;
140                 rects [8] = fb->var.xres_virtual - fb->x_margin;
141                 rects [9] = fb->y_margin;
142                 rects [10] = fb->var.xres_virtual;
143                 rects [11] = fb->var.yres_virtual;
144                 rects [12] = fb->x_margin;
145                 rects [13] = fb->var.yres_virtual - fb->y_margin;
146                 rects [14] = fb->var.xres_virtual - fb->x_margin;
147                 rects [15] = fb->var.yres_virtual;
148                 (*fb->fill)(fb, p, s, 4, rects);
149         } else {
150                 unsigned char *fb_base = fb->info.screen_base, *q;
151                 int skip_bytes = fb->y_margin * fb->var.xres_virtual;
152                 int scr_size = fb->var.xres_virtual * fb->var.yres_virtual;
153                 int h, he, incr, size;
154
155                 he = fb->var.yres;
156                 if (fb->var.bits_per_pixel == 1) {
157                         fb_base -= (skip_bytes + fb->x_margin) / 8;
158                         skip_bytes /= 8;
159                         scr_size /= 8;
160                         mymemset (fb_base, skip_bytes - fb->x_margin / 8);
161                         mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
162                         incr = fb->var.xres_virtual / 8;
163                         size = fb->x_margin / 8 * 2;
164                         for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
165                              h <= he; q += incr, h++)
166                                 mymemset (q, size);
167                 } else {
168                         fb_base -= (skip_bytes + fb->x_margin);
169                         memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
170                         memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
171                         incr = fb->var.xres_virtual;
172                         size = fb->x_margin * 2;
173                         for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
174                              h <= he; q += incr, h++)
175                                 memset (q, attr_bgcol(p,s), size);
176                 }
177         }
178 }
179
180 static void sun3fb_disp_setup(struct display *p)
181 {
182         struct fb_info_sbusfb *fb = sbusfbinfod(p);
183
184         if (fb->setup)
185                 fb->setup(p);   
186         sun3fb_clear_margin(p, 0);
187 }
188
189     /*
190      *  Get the Fixed Part of the Display
191      */
192
193 static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
194                           struct fb_info *info)
195 {
196         struct fb_info_sbusfb *fb = sbusfbinfo(info);
197
198         memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo));
199         return 0;
200 }
201
202     /*
203      *  Get the User Defined Part of the Display
204      */
205
206 static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
207                           struct fb_info *info)
208 {
209         struct fb_info_sbusfb *fb = sbusfbinfo(info);
210
211         memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
212         return 0;
213 }
214
215     /*
216      *  Set the User Defined Part of the Display
217      */
218
219 static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
220                         struct fb_info *info)
221 {
222         struct fb_info_sbusfb *fb = sbusfbinfo(info);
223
224         if (var->xres > fb->var.xres || var->yres > fb->var.yres ||
225             var->xres_virtual > fb->var.xres_virtual ||
226             var->yres_virtual > fb->var.yres_virtual ||
227             var->bits_per_pixel != fb->var.bits_per_pixel ||
228             var->nonstd ||
229             (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
230                 return -EINVAL;
231         memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
232         return 0;
233 }
234
235     /*
236      *  Hardware cursor
237      */
238      
239 static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
240
241 static void
242 sun3fb_cursor_timer_handler(unsigned long dev_addr)
243 {
244         struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr;
245         
246         if (!fb->setcursor) return;
247                                 
248         if (fb->cursor.mode & CURSOR_BLINK) {
249                 fb->cursor.enable ^= 1;
250                 fb->setcursor(fb);
251         }
252         
253         fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
254         add_timer(&fb->cursor.timer);
255 }
256
257 static void sun3fb_cursor(struct display *p, int mode, int x, int y)
258 {
259         struct fb_info_sbusfb *fb = sbusfbinfod(p);
260         
261         switch (mode) {
262         case CM_ERASE:
263                 fb->cursor.mode &= ~CURSOR_BLINK;
264                 fb->cursor.enable = 0;
265                 (*fb->setcursor)(fb);
266                 break;
267                                   
268         case CM_MOVE:
269         case CM_DRAW:
270                 if (fb->cursor.mode & CURSOR_SHAPE) {
271                         fb->cursor.size.fbx = fontwidth(p);
272                         fb->cursor.size.fby = fontheight(p);
273                         fb->cursor.chot.fbx = 0;
274                         fb->cursor.chot.fby = 0;
275                         fb->cursor.enable = 1;
276                         memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits));
277                         fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
278                         fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
279                         fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
280                         fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
281                         (*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
282                         (*fb->setcurshape) (fb);
283                 }
284                 fb->cursor.mode = CURSOR_BLINK;
285                 if (fontwidthlog(p))
286                         fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin;
287                 else
288                         fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin;
289                 if (fontheightlog(p))
290                         fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin;
291                 else
292                         fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin;
293                 (*fb->setcursor)(fb);
294                 break;
295         }
296 }
297
298     /*
299      *  Get the Colormap
300      */
301
302 static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
303                          struct fb_info *info)
304 {
305         if (con == info->currcon) /* current console? */
306                 return fb_get_cmap(cmap, kspc, sun3fb_getcolreg, info);
307         else if (fb_display[con].cmap.len) /* non default colormap? */
308                 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
309         else
310                 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
311         return 0;
312 }
313
314     /*
315      *  Set the Colormap
316      */
317
318 static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
319                          struct fb_info *info)
320 {
321         int err;
322
323         if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
324                 if ((err = fb_alloc_cmap(&fb_display[con].cmap, 1<<fb_display[con].var.bits_per_pixel, 0)))
325                         return err;
326         }
327         if (con == info->currcon) {                     /* current console? */
328                 err = fb_set_cmap(cmap, kspc, info);
329                 if (!err) {
330                         struct fb_info_sbusfb *fb = sbusfbinfo(info);
331                         
332                         if (fb->loadcmap)
333                                 (*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len);
334                 }
335                 return err;
336         } else
337                 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
338         return 0;
339 }
340
341     /*
342      *  Setup: parse used options
343      */
344
345 void __init sun3fb_setup(char *options)
346 {
347         char *p;
348         
349         for (p = options;;) {
350                 if (!strncmp(p, "font=", 5)) {
351                         int i;
352                         
353                         for (i = 0; i < sizeof(fontname) - 1; i++)
354                                 if (p[i+5] == ' ' || !p[i+5])
355                                         break;
356                         memcpy(fontname, p+5, i);
357                         fontname[i] = 0;
358                 } else if (!strncmp(p, "noblink", 7))
359                         curblink = 0;
360                 while (*p && *p != ' ' && *p != ',') p++;
361                 if (*p != ',') break;
362                 p++;
363         }
364
365         return;
366 }
367
368 static int sun3fbcon_switch(int con, struct fb_info *info)
369 {
370         int x_margin, y_margin;
371         struct fb_info_sbusfb *fb = sbusfbinfo(info);
372         int lastconsole;
373     
374         /* Do we have to save the colormap? */
375         if (fb_display[info->currcon].cmap.len)
376                 fb_get_cmap(&fb_display[info->currcon].cmap, 1, sun3fb_getcolreg, info);
377
378         if (info->display_fg) {
379                 lastconsole = info->display_fg->vc_num;
380                 if (lastconsole != con && 
381                     (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) ||
382                      fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con])))
383                         fb->cursor.mode |= CURSOR_SHAPE;
384         }
385         x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2;
386         y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2;
387         if (fb->margins)
388                 fb->margins(fb, &fb_display[con], x_margin, y_margin);
389         if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) {
390                 fb->x_margin = x_margin; fb->y_margin = y_margin;
391                 sun3fb_clear_margin(&fb_display[con], 0);
392         }
393         info->currcon = con;
394         /* Install new colormap */
395         do_install_cmap(con, info);
396         return 0;
397 }
398
399     /*
400      *  Update the `var' structure (called by fbcon.c)
401      */
402
403 static int sun3fbcon_updatevar(int con, struct fb_info *info)
404 {
405         /* Nothing */
406         return 0;
407 }
408
409     /*
410      *  Blank the display.
411      */
412
413 static int sun3fb_blank(int blank, struct fb_info *info)
414 {
415     struct fb_info_sbusfb *fb = sbusfbinfo(info);
416     
417     if (blank && fb->blank)
418         return fb->blank(fb);
419     else if (!blank && fb->unblank)
420         return fb->unblank(fb);
421     return 0;
422 }
423
424     /*
425      *  Read a single color register and split it into
426      *  colors/transparent. Return != 0 for invalid regno.
427      */
428
429 static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
430                           u_int *transp, struct fb_info *info)
431 {
432         struct fb_info_sbusfb *fb = sbusfbinfo(info);
433
434         if (!fb->color_map || regno > 255)
435                 return 1;
436         *red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0);
437         *green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1);
438         *blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2);
439         *transp = 0;
440         return 0;
441 }
442
443
444     /*
445      *  Set a single color register. The values supplied are already
446      *  rounded down to the hardware's capabilities (according to the
447      *  entries in the var structure). Return != 0 for invalid regno.
448      */
449
450 static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
451                             u_int transp, struct fb_info *info)
452 {
453         struct fb_info_sbusfb *fb = sbusfbinfo(info);
454
455         if (!fb->color_map || regno > 255)
456                 return 1;
457         red >>= 8;
458         green >>= 8;
459         blue >>= 8;
460         fb->color_map CM(regno, 0) = red;
461         fb->color_map CM(regno, 1) = green;
462         fb->color_map CM(regno, 2) = blue;
463         return 0;
464 }
465
466 static int sun3fb_set_font(struct display *p, int width, int height)
467 {
468         int w = p->var.xres_virtual, h = p->var.yres_virtual;
469         int depth = p->var.bits_per_pixel;
470         struct fb_info_sbusfb *fb = sbusfbinfod(p);
471         int x_margin, y_margin;
472         
473         if (depth > 8) depth = 8;
474         x_margin = (w % width) / 2;
475         y_margin = (h % height) / 2;
476
477         p->var.xres = w - 2*x_margin;
478         p->var.yres = h - 2*y_margin;
479         
480         fb->cursor.mode |= CURSOR_SHAPE;
481         
482         if (fb->margins)
483                 fb->margins(fb, p, x_margin, y_margin);
484         if (fb->x_margin != x_margin || fb->y_margin != y_margin) {
485                 fb->x_margin = x_margin; fb->y_margin = y_margin;
486                 sun3fb_clear_margin(p, 0);
487         }
488
489         return 1;
490 }
491
492 void sun3fb_palette(int enter)
493 {
494         int i;
495         struct display *p;
496         
497         for (i = 0; i < MAX_NR_CONSOLES; i++) {
498                 p = &fb_display[i];
499                 if (p->dispsw && p->dispsw->setup == sun3fb_disp_setup &&
500                     p->fb_info->display_fg &&
501                     p->fb_info->display_fg->vc_num == i) {
502                         struct fb_info_sbusfb *fb = sbusfbinfod(p);
503
504                         if (fb->restore_palette) {
505                                 if (enter)
506                                         fb->restore_palette(fb);
507                                 else if (vc_cons[i].d->vc_mode != KD_GRAPHICS)
508                                          vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
509                         }
510                 }
511         }
512 }
513
514     /*
515      *  Initialisation
516      */
517 static int __init sun3fb_init_fb(int fbtype, unsigned long addr)
518 {
519         static struct sbus_dev sdb;
520         struct fb_fix_screeninfo *fix;
521         struct fb_var_screeninfo *var;
522         struct display *disp;
523         struct fb_info_sbusfb *fb;
524         struct fbtype *type;
525         int linebytes, w, h, depth;
526         char *p = NULL;
527         
528         fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
529         if (!fb)
530                 return -ENOMEM;
531         
532         memset(fb, 0, sizeof(struct fb_info_sbusfb));
533         fix = &fb->fix;
534         var = &fb->var;
535         disp = &fb->disp;
536         type = &fb->type;
537         
538         sdb.reg_addrs[0].phys_addr = addr;
539         fb->sbdp = &sdb;
540
541         type->fb_type = fbtype;
542         
543         type->fb_height = h = 900;
544         type->fb_width  = w = 1152;
545 sizechange:
546         type->fb_depth  = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
547         linebytes = w * depth / 8;
548         type->fb_size   = PAGE_ALIGN((linebytes) * h);
549 /*      
550         fb->x_margin = (w & 7) / 2;
551         fb->y_margin = (h & 15) / 2;
552 */
553         fb->x_margin = fb->y_margin = 0;
554
555         var->xres_virtual = w;
556         var->yres_virtual = h;
557         var->xres = w - 2*fb->x_margin;
558         var->yres = h - 2*fb->y_margin;
559         
560         var->bits_per_pixel = depth;
561         var->height = var->width = -1;
562         var->pixclock = 10000;
563         var->vmode = FB_VMODE_NONINTERLACED;
564         var->red.length = var->green.length = var->blue.length = 8;
565
566         fix->line_length = linebytes;
567         fix->smem_len = type->fb_size;
568         fix->type = FB_TYPE_PACKED_PIXELS;
569         fix->visual = FB_VISUAL_PSEUDOCOLOR;
570         
571         fb->info.fbops = &sun3fb_ops;
572         fb->info.disp = disp;
573         fb->info.currcon = -1;
574         strcpy(fb->info.fontname, fontname);
575         fb->info.changevar = NULL;
576         fb->info.switch_con = &sun3fbcon_switch;
577         fb->info.updatevar = &sun3fbcon_updatevar;
578         fb->info.flags = FBINFO_FLAG_DEFAULT;
579         
580         fb->cursor.hwsize.fbx = 32;
581         fb->cursor.hwsize.fby = 32;
582         
583         if (depth > 1 && !fb->color_map) {
584                 if((fb->color_map = kmalloc(256 * 3, GFP_ATOMIC))==NULL)
585                         return -ENOMEM;
586         }
587                         
588         switch(fbtype) {
589 #ifdef CONFIG_FB_CGSIX
590         case FBTYPE_SUNFAST_COLOR:
591                 p = cgsixfb_init(fb); break;
592 #endif
593 #ifdef CONFIG_FB_BWTWO
594         case FBTYPE_SUN2BW:
595                 p = bwtwofb_init(fb); break;
596 #endif
597 #ifdef CONFIG_FB_CGTHREE
598         case FBTYPE_SUN4COLOR:
599         case FBTYPE_SUN3COLOR:
600                 type->fb_size = 0x100000;
601                 p = cgthreefb_init(fb); break;
602 #endif
603         }
604         fix->smem_start = (unsigned long)fb->info.screen_base;  // FIXME
605         
606         if (!p) {
607                 kfree(fb);
608                 return -ENODEV;
609         }
610         
611         if (p == SBUSFBINIT_SIZECHANGE)
612                 goto sizechange;
613
614         disp->dispsw = &fb->dispsw;
615         if (fb->setcursor) {
616                 fb->dispsw.cursor = sun3fb_cursor;
617                 if (curblink) {
618                         fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
619                         init_timer(&fb->cursor.timer);
620                         fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
621                         fb->cursor.timer.data = (unsigned long)fb;
622                         fb->cursor.timer.function = sun3fb_cursor_timer_handler;
623                         add_timer(&fb->cursor.timer);
624                 }
625         }
626         fb->cursor.mode = CURSOR_SHAPE;
627         fb->dispsw.set_font = sun3fb_set_font;
628         fb->setup = fb->dispsw.setup;
629         fb->dispsw.setup = sun3fb_disp_setup;
630         fb->dispsw.clear_margins = NULL;
631
632         disp->var = *var;
633         disp->visual = fix->visual;
634         disp->type = fix->type;
635         disp->type_aux = fix->type_aux;
636         disp->line_length = fix->line_length;
637         
638         if (fb->blank)
639                 disp->can_soft_blank = 1;
640
641         sun3fb_set_var(var, -1, &fb->info);
642
643         if (register_framebuffer(&fb->info) < 0) {
644                 kfree(fb);
645                 return -EINVAL;
646         }
647         printk("fb%d: %s\n", fb->info.node, p);
648
649         return 0;
650 }
651
652
653 int __init sun3fb_init(void)
654 {
655         extern int con_is_present(void);
656         unsigned long addr;
657         char p4id;
658         
659         if (!con_is_present()) return -ENODEV;
660 #ifdef CONFIG_SUN3
661         switch(*(romvec->pv_fbtype))
662         {
663         case FBTYPE_SUN2BW:
664                 addr = 0xfe20000;
665                 return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
666         case FBTYPE_SUN3COLOR:
667         case FBTYPE_SUN4COLOR:
668                 if(idprom->id_machtype != (SM_SUN3|SM_3_60)) {
669                         printk("sun3fb: cgthree/four only supported on 3/60\n");
670                         return -ENODEV;
671                 }
672                 
673                 addr = CGFOUR_OBMEM_ADDR;
674                 return sun3fb_init_fb(*(romvec->pv_fbtype), addr);
675         default:
676                 printk("sun3fb: unsupported framebuffer\n");
677                 return -ENODEV;
678         }
679 #else
680         addr = SUN3X_VIDEO_BASE;
681         p4id = *(char *)SUN3X_VIDEO_P4ID;
682
683         p4id = (p4id == 0x45) ? p4id : (p4id & 0xf0);
684         switch (p4id) {
685                 case 0x00:
686                         return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
687 #if 0 /* not yet */
688                 case 0x40:
689                         return sun3fb_init_fb(FBTYPE_SUN4COLOR, addr);
690                         break;
691                 case 0x45:
692                         return sun3fb_init_fb(FBTYPE_SUN8COLOR, addr);
693                         break;
694 #endif
695                 case 0x60:
696                         return sun3fb_init_fb(FBTYPE_SUNFAST_COLOR, addr);
697         }
698 #endif                  
699         
700         return -ENODEV;
701 }
702
703 MODULE_LICENSE("GPL");