File: /usr/src/linux/drivers/video/igafb.c

1     /*
2      *  linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
3      *
4      *      Copyright (C) 1998  Vladimir Roganov and Gleb Raiko
5      *
6      *  This driver is partly based on the Frame buffer device for ATI Mach64
7      *  and partially on VESA-related code.
8      *
9      *      Copyright (C) 1997-1998  Geert Uytterhoeven
10      *      Copyright (C) 1998  Bernd Harries
11      *      Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
12      *
13      *  This file is subject to the terms and conditions of the GNU General Public
14      *  License. See the file COPYING in the main directory of this archive for
15      *  more details.
16      */
17     
18     /******************************************************************************
19     
20       TODO:
21            Despite of IGA Card has advanced graphic acceleration, 
22            initial version is almost dummy and does not support it.
23            Support for video modes and acceleration must be added
24            together with accelerated X-Windows driver implementation.
25     
26            Most important thing at this moment is that we have working
27            JavaEngine1  console & X  with new console interface.
28     
29     ******************************************************************************/
30     
31     #include <linux/module.h>
32     #include <linux/kernel.h>
33     #include <linux/errno.h>
34     #include <linux/string.h>
35     #include <linux/mm.h>
36     #include <linux/tty.h>
37     #include <linux/slab.h>
38     #include <linux/vmalloc.h>
39     #include <linux/delay.h>
40     #include <linux/interrupt.h>
41     #include <linux/fb.h>
42     #include <linux/selection.h>
43     #include <linux/console.h>
44     #include <linux/init.h>
45     #include <linux/pci.h>
46     #include <linux/nvram.h>
47     #include <linux/kd.h>
48     #include <linux/vt_kern.h>
49     
50     #include <asm/io.h>
51     
52     #ifdef __sparc__
53     #include <asm/pbm.h>
54     #include <asm/pcic.h>
55     #endif
56     
57     #include <video/fbcon.h>
58     #include <video/fbcon-cfb8.h>
59     #include <video/fbcon-cfb16.h>
60     #include <video/fbcon-cfb24.h>
61     #include <video/fbcon-cfb32.h>
62     
63     #include "iga.h"
64     
65     static char igafb_name[16] = "IGA 1682";
66     static char fontname[40] __initdata = { 0 };
67     
68     struct pci_mmap_map {
69         unsigned long voff;
70         unsigned long poff;
71         unsigned long size;
72         unsigned long prot_flag;
73         unsigned long prot_mask;
74     };
75     
76     struct fb_info_iga {
77         struct fb_info fb_info;
78         unsigned long frame_buffer_phys;
79         char *frame_buffer;
80         unsigned long io_base_phys;
81         unsigned long io_base;
82         u32 total_vram;
83         struct pci_mmap_map *mmap_map;
84         struct { u_short blue, green, red, pad; } palette[256];
85         int video_cmap_len;
86         int currcon;
87         struct display disp;
88         struct display_switch dispsw; 
89         union {
90     #ifdef FBCON_HAS_CFB16
91     	    u16 cfb16[16];  
92     #endif
93     #ifdef FBCON_HAS_CFB24
94     	    u32 cfb24[16];
95     #endif
96     #ifdef FBCON_HAS_CFB32
97     	    u32 cfb32[16];
98     #endif
99         } fbcon_cmap;
100     #ifdef __sparc__
101         u8 open;
102         u8 mmaped;
103         int vtconsole;
104         int consolecnt;
105     #endif
106     };
107     
108     struct fb_var_screeninfo default_var = {
109         /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
110         640, 480, 640, 480, 0, 0, 8, 0,
111         {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
112         0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
113         0, FB_VMODE_NONINTERLACED
114     };
115     
116     #ifdef __sparc__
117     struct fb_var_screeninfo default_var_1024x768 __initdata = {
118         /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
119         1024, 768, 1024, 768, 0, 0, 8, 0,
120         {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
121         0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
122         FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
123     };
124     
125     struct fb_var_screeninfo default_var_1152x900 __initdata = {
126         /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
127         1152, 900, 1152, 900, 0, 0, 8, 0,
128         {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
129         0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
130         FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
131     };
132     
133     struct fb_var_screeninfo default_var_1280x1024 __initdata = {
134         /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
135         1280, 1024, 1280, 1024, 0, 0, 8, 0,
136         {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
137         0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
138         FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
139     };
140     
141     /*
142      *   Memory-mapped I/O functions for Sparc PCI
143      *
144      * On sparc we happen to access I/O with memory mapped functions too.
145      */ 
146     #define pci_inb(info, reg)        readb(info->io_base+(reg))
147     #define pci_outb(info, val, reg)  writeb(val, info->io_base+(reg))
148     
149     static inline unsigned int iga_inb(struct fb_info_iga *info,
150     				   unsigned int reg, unsigned int idx )
151     {
152             pci_outb(info, idx, reg);
153             return pci_inb(info, reg + 1);
154     }
155     
156     static inline void iga_outb(struct fb_info_iga *info, unsigned char val,
157     			    unsigned int reg, unsigned int idx )
158     {
159             pci_outb(info, idx, reg);
160             pci_outb(info, val, reg+1);
161     }
162     
163     #endif /* __sparc__ */
164     
165     /*
166      *  Very important functionality for the JavaEngine1 computer:
167      *  make screen border black (usign special IGA registers) 
168      */
169     static void iga_blank_border(struct fb_info_iga *info)
170     {
171             int i;
172     
173     #if 0
174     	/*
175     	 * PROM does this for us, so keep this code as a reminder
176     	 * about required read from 0x3DA and writing of 0x20 in the end.
177     	 */
178     	(void) pci_inb(info, 0x3DA);		/* required for every access */
179     	pci_outb(info, IGA_IDX_VGA_OVERSCAN, IGA_ATTR_CTL);
180     	(void) pci_inb(info, IGA_ATTR_CTL+1);
181     	pci_outb(info, 0x38, IGA_ATTR_CTL);
182     	pci_outb(info, 0x20, IGA_ATTR_CTL);	/* re-enable visual */
183     #endif
184     	/*
185     	 * This does not work as it was designed because the overscan
186     	 * color is looked up in the palette. Therefore, under X11
187     	 * overscan changes color.
188     	 */
189     	for (i=0; i < 3; i++)
190     		iga_outb(info, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
191     }
192     
193     
194     /*
195      *  Frame buffer device API
196      */
197     
198     static int igafb_update_var(int con, struct fb_info *info)
199     {
200             return 0;
201     }
202     
203     static int igafb_get_fix(struct fb_fix_screeninfo *fix, int con,
204                              struct fb_info *info)
205     {
206             struct fb_info_iga *fb = (struct fb_info_iga*)info;
207     
208             memset(fix, 0, sizeof(struct fb_fix_screeninfo));
209             strcpy(fix->id, igafb_name);
210     
211             fix->smem_start = (unsigned long) fb->frame_buffer;
212             fix->smem_len = fb->total_vram;
213             fix->xpanstep = 0;
214             fix->ypanstep = 0;
215             fix->ywrapstep = 0;
216     
217     	fix->type = FB_TYPE_PACKED_PIXELS;
218     	fix->type_aux = 0;
219     	fix->line_length = default_var.xres * (default_var.bits_per_pixel/8);
220     	fix->visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR
221     		                                      : FB_VISUAL_DIRECTCOLOR;
222             return 0;
223     }
224     
225     static int igafb_get_var(struct fb_var_screeninfo *var, int con,
226                              struct fb_info *info)
227     {
228             if(con == -1)
229                     memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
230             else
231                     *var = fb_display[con].var;
232             return 0;
233     }
234     
235     static int igafb_set_var(struct fb_var_screeninfo *var, int con,
236                              struct fb_info *info)
237     {
238             memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
239             return 0;
240     }
241     
242     #ifdef __sparc__
243     static int igafb_mmap(struct fb_info *info, struct file *file,
244     		      struct vm_area_struct *vma)
245     {
246     	struct fb_info_iga *fb = (struct fb_info_iga *)info;
247     	unsigned int size, page, map_size = 0;
248     	unsigned long map_offset = 0;
249     	int i;
250     
251     	if (!fb->mmap_map)
252     		return -ENXIO;
253     
254     	size = vma->vm_end - vma->vm_start;
255     
256     	/* To stop the swapper from even considering these pages. */
257     	vma->vm_flags |= (VM_SHM | VM_LOCKED);
258     
259     	/* Each page, see which map applies */
260     	for (page = 0; page < size; ) {
261     		map_size = 0;
262     		for (i = 0; fb->mmap_map[i].size; i++) {
263     			unsigned long start = fb->mmap_map[i].voff;
264     			unsigned long end = start + fb->mmap_map[i].size;
265     			unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT) + page;
266     
267     			if (start > offset)
268     				continue;
269     			if (offset >= end)
270     				continue;
271     
272     			map_size = fb->mmap_map[i].size - (offset - start);
273     			map_offset = fb->mmap_map[i].poff + (offset - start);
274     			break;
275     		}
276     		if (!map_size) {
277     			page += PAGE_SIZE;
278     			continue;
279     		}
280     		if (page + map_size > size)
281     			map_size = size - page;
282     
283     		pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
284     		pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
285     
286     		if (remap_page_range(vma->vm_start + page, map_offset,
287     				     map_size, vma->vm_page_prot))
288     			return -EAGAIN;
289     
290     		page += map_size;
291     	}
292     
293     	if (!map_size)
294     		return -EINVAL;
295     
296     	vma->vm_flags |= VM_IO;
297     
298     	if (!fb->mmaped) {
299     		int lastconsole = 0;
300     
301     		if (info->display_fg)
302     			lastconsole = info->display_fg->vc_num;
303     		fb->mmaped = 1;
304     		if (fb->consolecnt && fb_display[lastconsole].fb_info ==info) {
305     			fb->vtconsole = lastconsole;
306     			vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
307     		}
308     	}
309     	return 0;
310     }
311     #endif /* __sparc__ */
312     
313     
314     static int iga_getcolreg(unsigned regno, unsigned *red, unsigned *green,
315                               unsigned *blue, unsigned *transp,
316                               struct fb_info *fb_info)
317     {
318             /*
319              *  Read a single color register and split it into colors/transparent.
320              *  Return != 0 for invalid regno.
321              */
322     	struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
323     
324             if (regno >= info->video_cmap_len)
325                     return 1;
326     
327     	*red    = info->palette[regno].red;
328     	*green  = info->palette[regno].green;
329     	*blue   = info->palette[regno].blue;
330     	*transp = 0;
331     	return 0;
332     }
333     
334     static int iga_setcolreg(unsigned regno, unsigned red, unsigned green,
335                               unsigned blue, unsigned transp,
336                               struct fb_info *fb_info)
337     {
338             /*
339              *  Set a single color register. The values supplied are
340              *  already rounded down to the hardware's capabilities
341              *  (according to the entries in the `var' structure). Return
342              *  != 0 for invalid regno.
343              */
344             
345     	struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
346     
347             if (regno >= info->video_cmap_len)
348                     return 1;
349     
350             info->palette[regno].red   = red;
351             info->palette[regno].green = green;
352             info->palette[regno].blue  = blue;
353     
354     	pci_outb(info, regno, DAC_W_INDEX);
355     	pci_outb(info, red,   DAC_DATA);
356     	pci_outb(info, green, DAC_DATA);
357     	pci_outb(info, blue,  DAC_DATA);
358     
359     	if (regno < 16) {
360     		switch (default_var.bits_per_pixel) {
361     #ifdef FBCON_HAS_CFB16
362     		case 16:
363     			info->fbcon_cmap.cfb16[regno] = 
364     				(regno << 10) | (regno << 5) | regno;
365     			break;
366     #endif
367     #ifdef FBCON_HAS_CFB24
368     		case 24:
369     			info->fbcon_cmap.cfb24[regno] = 
370     				(regno << 16) | (regno << 8) | regno;
371     		break;
372     #endif
373     #ifdef FBCON_HAS_CFB32
374     		case 32:
375     			{ int i;
376     			i = (regno << 8) | regno;
377     			info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
378     			}
379     			break;
380     #endif
381     		}
382     	}
383     	return 0;
384     }
385     
386     static void do_install_cmap(int con, struct fb_info *fb_info)
387     {
388     	struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
389     
390             if (con != info->currcon)
391                     return;
392             if (fb_display[con].cmap.len)
393                     fb_set_cmap(&fb_display[con].cmap, 1,
394                                 iga_setcolreg, &info->fb_info);
395             else
396                     fb_set_cmap(fb_default_cmap(info->video_cmap_len), 1, 
397     			    iga_setcolreg, &info->fb_info);
398     }
399     
400     static int igafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
401                                struct fb_info *fb_info)
402     {
403     	struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
404     	
405             if (con == info->currcon) /* current console? */
406                     return fb_get_cmap(cmap, kspc, iga_getcolreg, &info->fb_info);
407             else if (fb_display[con].cmap.len) /* non default colormap? */
408                     fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
409             else
410                     fb_copy_cmap(fb_default_cmap(info->video_cmap_len),
411                          cmap, kspc ? 0 : 2);
412             return 0;
413     }
414     
415     static int igafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
416     	                  struct fb_info *info)
417     {
418             int err;
419     	struct fb_info_iga *fb = (struct fb_info_iga*) info;
420     
421             if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
422                     err = fb_alloc_cmap(&fb_display[con].cmap,
423     				    fb->video_cmap_len,0);
424                     if (err)
425                             return err;
426             }
427             if (con == fb->currcon)                     /* current console? */
428                     return fb_set_cmap(cmap, kspc, iga_setcolreg, info);
429             else
430                     fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
431             return 0;
432     }
433     
434     /*
435      * Framebuffer option structure
436      */
437     static struct fb_ops igafb_ops = {
438     	owner:		THIS_MODULE,
439     	fb_get_fix:	igafb_get_fix,
440     	fb_get_var:	igafb_get_var,
441     	fb_set_var:	igafb_set_var,
442     	fb_get_cmap:	igafb_get_cmap,
443     	fb_set_cmap:	igafb_set_cmap,
444     #ifdef __sparc__
445     	fb_mmap:	igafb_mmap,
446     #endif
447     };
448     
449     static void igafb_set_disp(int con, struct fb_info_iga *info)
450     {
451             struct fb_fix_screeninfo fix;
452             struct display *display;
453             struct display_switch *sw;
454     
455             if (con >= 0)
456                     display = &fb_display[con];
457             else 
458                     display = &info->disp;        /* used during initialization */
459     
460             igafb_get_fix(&fix, con, &info->fb_info);
461     
462             memset(display, 0, sizeof(struct display));
463             display->screen_base = info->frame_buffer;
464             display->visual = fix.visual;
465             display->type = fix.type;
466             display->type_aux = fix.type_aux;
467             display->ypanstep = fix.ypanstep;
468             display->ywrapstep = fix.ywrapstep;
469             display->line_length = fix.line_length;
470             display->next_line = fix.line_length;
471             display->can_soft_blank = 0; 
472             display->inverse = 0;
473             igafb_get_var(&display->var, -1, &info->fb_info);
474     
475             switch (default_var.bits_per_pixel) {
476     #ifdef FBCON_HAS_CFB8
477             case 8:
478                     sw = &fbcon_cfb8;
479                     break;
480     #endif
481     #ifdef FBCON_HAS_CFB16
482             case 15:
483             case 16:
484                     sw = &fbcon_cfb16;
485     		display->dispsw_data = info->fbcon_cmap.cfb16;
486                     break;
487     #endif
488     #ifdef FBCON_HAS_CFB24
489     	case 24:
490     		sw = &fbcon_cfb24;
491     		display->dispsw_data = info->fbcon_cmap.cfb24;
492     		break;
493     #endif
494     #ifdef FBCON_HAS_CFB32
495             case 32:
496                     sw = &fbcon_cfb32;
497     		display->dispsw_data = info->fbcon_cmap.cfb32;
498                     break;
499     #endif
500             default:
501     		printk(KERN_WARNING "igafb_set_disp: unknown resolution %d\n",
502     		    default_var.bits_per_pixel);
503                     return;
504             }
505             memcpy(&info->dispsw, sw, sizeof(*sw));
506             display->dispsw = &info->dispsw;
507     
508     	display->scrollmode = SCROLL_YREDRAW;
509     	info->dispsw.bmove = fbcon_redraw_bmove;
510     }
511     
512     static int igafb_switch(int con, struct fb_info *fb_info)
513     {
514     	struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
515     
516             /* Do we have to save the colormap? */
517             if (fb_display[info->currcon].cmap.len)
518                     fb_get_cmap(&fb_display[info->currcon].cmap, 1,
519                                 iga_getcolreg, fb_info);
520     
521     	info->currcon = con;
522     	/* Install new colormap */
523     	do_install_cmap(con, fb_info);
524     	igafb_update_var(con, fb_info);
525             return 1;
526     }
527     
528     
529     
530     /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
531     
532     static void igafb_blank(int blank, struct fb_info *info)
533     {
534             /* Not supported */
535     }
536     
537     
538     static int __init iga_init(struct fb_info_iga *info)
539     {
540             char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) 
541     		                                         & MEM_SIZE_ALIAS;
542             switch (vramsz) {
543             case MEM_SIZE_1M:
544                     info->total_vram = 0x100000;
545                     break;
546             case MEM_SIZE_2M:
547                     info->total_vram = 0x200000;
548                     break;
549             case MEM_SIZE_4M:
550             case MEM_SIZE_RESERVED:
551                     info->total_vram = 0x400000;
552                     break;
553             }
554     
555             if (default_var.bits_per_pixel > 8) {
556                     info->video_cmap_len = 16;
557             } else {
558                     info->video_cmap_len = 256;
559             }
560     	{
561     		int j, k;
562     		for (j = 0; j < 16; j++) {
563     			k = color_table[j];
564     			info->palette[j].red = default_red[k];
565     			info->palette[j].green = default_grn[k];
566     			info->palette[j].blue = default_blu[k];
567     		}
568     	}
569     
570     	strcpy(info->fb_info.modename, igafb_name);
571     	info->fb_info.node = -1;
572     	info->fb_info.fbops = &igafb_ops;
573     	info->fb_info.disp = &info->disp;
574     	strcpy(info->fb_info.fontname, fontname);
575     	info->fb_info.changevar = NULL;
576     	info->fb_info.switch_con = &igafb_switch;
577     	info->fb_info.updatevar = &igafb_update_var;
578     	info->fb_info.blank = &igafb_blank;
579     	info->fb_info.flags=FBINFO_FLAG_DEFAULT;
580     
581     	igafb_set_disp(-1, info);
582     
583     	if (register_framebuffer(&info->fb_info) < 0)
584     		return 0;
585     
586     	printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
587     	       GET_FB_IDX(info->fb_info.node), igafb_name, 
588     	       info->frame_buffer_phys, info->total_vram >> 20);
589     
590     	iga_blank_border(info); 
591     	return 1;
592     }
593     
594     int __init igafb_init(void)
595     {
596             struct pci_dev *pdev;
597             struct fb_info_iga *info;
598             unsigned long addr;
599             extern int con_is_present(void);
600     	int iga2000 = 0;
601     
602             /* Do not attach when we have a serial console. */
603             if (!con_is_present())
604                     return -ENXIO;
605     
606             pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 
607                                    PCI_DEVICE_ID_INTERG_1682, 0);
608     	if (pdev == NULL) {
609     		/*
610     		 * XXX We tried to use cyber2000fb.c for IGS 2000.
611     		 * But it does not initialize the chip in JavaStation-E, alas.
612     		 */
613             	pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
614             	if(pdev == NULL) {
615             	        return -ENXIO;
616     		}
617     		iga2000 = 1;
618     	}
619     
620             info = kmalloc(sizeof(struct fb_info_iga), GFP_ATOMIC);
621             if (!info) {
622                     printk("igafb_init: can't alloc fb_info_iga\n");
623                     return -ENOMEM;
624             }
625             memset(info, 0, sizeof(struct fb_info_iga));
626     
627     	if ((addr = pdev->resource[0].start) == 0) {
628                     printk("igafb_init: no memory start\n");
629     		kfree(info);
630     		return -ENXIO;
631     	}
632     
633     	if ((info->frame_buffer = ioremap(addr, 1024*1024*2)) == 0) {
634                     printk("igafb_init: can't remap %lx[2M]\n", addr);
635     		kfree(info);
636     		return -ENXIO;
637     	}
638     
639     	info->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
640     
641     #ifdef __sparc__
642     	/*
643     	 * The following is sparc specific and this is why:
644     	 *
645     	 * IGS2000 has its I/O memory mapped and we want
646     	 * to generate memory cycles on PCI, e.g. do ioremap(),
647     	 * then readb/writeb() as in Documentation/IO-mapping.txt.
648     	 *
649     	 * IGS1682 is more traditional, it responds to PCI I/O
650     	 * cycles, so we want to access it with inb()/outb().
651     	 *
652     	 * On sparc, PCIC converts CPU memory access within
653     	 * phys window 0x3000xxxx into PCI I/O cycles. Therefore
654     	 * we may use readb/writeb to access them with IGS1682.
655     	 *
656     	 * We do not take io_base_phys from resource[n].start
657     	 * on IGS1682 because that chip is BROKEN. It does not
658     	 * have a base register for I/O. We just "know" what its
659     	 * I/O addresses are.
660     	 */
661     	if (iga2000) {
662     		info->io_base_phys = info->frame_buffer_phys | 0x00800000;
663     	} else {
664     		info->io_base_phys = 0x30000000;	/* XXX */
665     	}
666     	if ((info->io_base = (int) ioremap(info->io_base_phys, 0x1000)) == 0) {
667                     printk("igafb_init: can't remap %lx[4K]\n", info->io_base_phys);
668     		iounmap((void *)info->frame_buffer);
669                     kfree(info);
670     		return -ENXIO;
671     	}
672     
673     	/*
674     	 * Figure mmap addresses from PCI config space.
675     	 * We need two regions: for video memory and for I/O ports.
676     	 * Later one can add region for video coprocessor registers.
677     	 * However, mmap routine loops until size != 0, so we put
678     	 * one additional region with size == 0. 
679     	 */
680     
681     	info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
682     	if (!info->mmap_map) {
683     		printk("igafb_init: can't alloc mmap_map\n");
684     		iounmap((void *)info->io_base);
685     		iounmap(info->frame_buffer);
686                     kfree(info);
687     		return -ENOMEM;
688     	}
689     
690     	memset(info->mmap_map, 0, 4 * sizeof(*info->mmap_map));
691     
692     	/*
693     	 * Set default vmode and cmode from PROM properties.
694     	 */
695     	{
696                     struct pcidev_cookie *cookie = pdev->sysdata;
697                     int node = cookie->prom_node;
698                     int width = prom_getintdefault(node, "width", 1024);
699                     int height = prom_getintdefault(node, "height", 768);
700                     int depth = prom_getintdefault(node, "depth", 8);
701                     switch (width) {
702                         case 1024:
703                             if (height == 768)
704                                 default_var = default_var_1024x768;
705                             break;
706                         case 1152:
707                             if (height == 900)
708                                 default_var = default_var_1152x900;
709                             break;
710                         case 1280:
711                             if (height == 1024)
712                                 default_var = default_var_1280x1024;
713                             break;
714                         default:
715                             break;
716                     }
717     
718                     switch (depth) {
719                         case 8:
720                             default_var.bits_per_pixel = 8;
721                             break;
722                         case 16:
723                             default_var.bits_per_pixel = 16;
724                             break;
725                         case 24:
726                             default_var.bits_per_pixel = 24;
727                             break;
728                         case 32:
729                             default_var.bits_per_pixel = 32;
730                             break;
731                         default:
732                             break;
733                     }
734                 }
735     
736     #endif
737     
738     	if (!iga_init(info)) {
739     		iounmap((void *)info->io_base);
740     		iounmap(info->frame_buffer);
741     		if (info->mmap_map)
742     			kfree(info->mmap_map);
743     		kfree(info);
744             }
745     
746     #ifdef __sparc__
747     	    /*
748     	     * Add /dev/fb mmap values.
749     	     */
750     	    
751     	    /* First region is for video memory */
752     	    info->mmap_map[0].voff = 0x0;  
753     	    info->mmap_map[0].poff = info->frame_buffer_phys & PAGE_MASK;
754     	    info->mmap_map[0].size = info->total_vram   & PAGE_MASK;
755     	    info->mmap_map[0].prot_mask = SRMMU_CACHE;
756     	    info->mmap_map[0].prot_flag = SRMMU_WRITE;
757     
758     	    /* Second region is for I/O ports */
759     	    info->mmap_map[1].voff = info->frame_buffer_phys & PAGE_MASK;
760     	    info->mmap_map[1].poff = info->io_base_phys & PAGE_MASK;
761     	    info->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
762     	    info->mmap_map[1].prot_mask = SRMMU_CACHE;
763     	    info->mmap_map[1].prot_flag = SRMMU_WRITE;
764     #endif /* __sparc__ */
765     
766     	return 0;
767     }
768     
769     int __init igafb_setup(char *options)
770     {
771         char *this_opt;
772     
773         if (!options || !*options)
774             return 0;
775     
776         for (this_opt = strtok(options, ","); this_opt;
777              this_opt = strtok(NULL, ",")) {
778             if (!strncmp(this_opt, "font:", 5)) {
779                     char *p;
780                     int i;
781     
782                     p = this_opt + 5;
783                     for (i = 0; i < sizeof(fontname) - 1; i++)
784                             if (!*p || *p == ' ' || *p == ',')
785                                     break;
786                     memcpy(fontname, this_opt + 5, i);
787                     fontname[i] = 0;
788             }
789         }
790         return 0;
791     }
792     
793     MODULE_LICENSE("GPL");
794