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

1     /*
2      * linux/drivers/video/hgafb.c -- Hercules graphics adaptor frame buffer device
3      * 
4      *      Created 25 Nov 1999 by Ferenc Bakonyi (fero@drama.obuda.kando.hu)
5      *      Based on skeletonfb.c by Geert Uytterhoeven and
6      *               mdacon.c by Andrew Apted
7      *
8      * History:
9      *
10      * - Revision 0.1.7 (23 Jan 2001): fix crash resulting from MDA only cards 
11      *				   being detected as Hercules.	 (Paul G.)
12      * - Revision 0.1.6 (17 Aug 2000): new style structs
13      *                                 documentation
14      * - Revision 0.1.5 (13 Mar 2000): spinlocks instead of saveflags();cli();etc
15      *                                 minor fixes
16      * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for 
17      *                                  HGA-only systems
18      * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure
19      *                                 screen is cleared after rmmod
20      *                                 virtual resolutions
21      *                                 kernel parameter 'video=hga:font:{fontname}'
22      *                                 module parameter 'font={fontname}'
23      *                                 module parameter 'nologo={0|1}'
24      *                                 the most important: boot logo :)
25      * - Revision 0.1.0  (6 Dec 1999): faster scrolling and minor fixes
26      * - First release  (25 Nov 1999)
27      *
28      * This file is subject to the terms and conditions of the GNU General Public
29      * License.  See the file COPYING in the main directory of this archive
30      * for more details.
31      */
32     
33     #include <linux/module.h>
34     #include <linux/kernel.h>
35     #include <linux/errno.h>
36     #include <linux/spinlock.h>
37     #include <linux/string.h>
38     #include <linux/mm.h>
39     #include <linux/tty.h>
40     #include <linux/slab.h>
41     #include <linux/delay.h>
42     #include <linux/fb.h>
43     #include <linux/init.h>
44     #include <linux/ioport.h>
45     #include <asm/io.h>
46     #include <asm/vga.h>
47     #include <video/fbcon.h>
48     #include <video/fbcon-hga.h>
49     
50     #ifdef MODULE
51     
52     #define INCLUDE_LINUX_LOGO_DATA
53     #include <linux/linux_logo.h>
54     
55     #endif /* MODULE */
56     
57     #if 0
58     #define DPRINTK(args...) printk(KERN_DEBUG __FILE__": " ##args)
59     #else
60     #define DPRINTK(args...)
61     #endif
62     
63     #if 0
64     #define CHKINFO(ret) if (info != &fb_info) { printk(KERN_DEBUG __FILE__": This should never happen, line:%d \n", __LINE__); return ret; }
65     #else
66     #define CHKINFO(ret)
67     #endif
68     
69     /* Description of the hardware layout */
70     
71     static unsigned long hga_vram_base;		/* Base of video memory */
72     static unsigned long hga_vram_len;		/* Size of video memory */
73     
74     #define HGA_TXT			0
75     #define HGA_GFX			1
76     
77     static int hga_mode = -1;			/* 0 = txt, 1 = gfx mode */
78     
79     static enum { TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } hga_type;
80     static char *hga_type_name;
81     
82     #define HGA_INDEX_PORT		0x3b4		/* Register select port */
83     #define HGA_VALUE_PORT		0x3b5		/* Register value port */
84     #define HGA_MODE_PORT		0x3b8		/* Mode control port */
85     #define HGA_STATUS_PORT		0x3ba		/* Status and Config port */
86     #define HGA_GFX_PORT		0x3bf		/* Graphics control port */
87     
88     /* HGA register values */
89     
90     #define HGA_CURSOR_BLINKING	0x00
91     #define HGA_CURSOR_OFF		0x20
92     #define HGA_CURSOR_SLOWBLINK	0x60
93     
94     #define HGA_MODE_GRAPHICS	0x02
95     #define HGA_MODE_VIDEO_EN	0x08
96     #define HGA_MODE_BLINK_EN	0x20
97     #define HGA_MODE_GFX_PAGE1	0x80
98     
99     #define HGA_STATUS_HSYNC	0x01
100     #define HGA_STATUS_VSYNC	0x80
101     #define HGA_STATUS_VIDEO	0x08
102     
103     #define HGA_CONFIG_COL132	0x08
104     #define HGA_GFX_MODE_EN		0x01
105     #define HGA_GFX_PAGE_EN		0x02
106     
107     /* Global locks */
108     
109     static spinlock_t hga_reg_lock = SPIN_LOCK_UNLOCKED;
110     
111     /* Framebuffer driver structures */
112     
113     static struct fb_var_screeninfo hga_default_var = {
114     	xres:		720,
115     	yres:		348,
116     	xres_virtual:	720,
117     	yres_virtual:	348,
118     	xoffset:	0,
119     	yoffset:	0,
120     	bits_per_pixel:	1,
121     	grayscale:	0,
122     	red:		{0, 1, 0},
123     	green:		{0, 1, 0},
124     	blue:		{0, 1, 0},
125     	transp:		{0, 0, 0},
126     	nonstd:		0,			/* (FB_NONSTD_HGA ?) */
127     	activate:	0,
128     	height:		-1,
129     	width:		-1,
130     	accel_flags:	0,
131     	/* pixclock */
132     	/* left_margin, right_margin */
133     	/* upper_margin, lower_margin */
134     	/* hsync_len, vsync_len */
135     	/* sync */
136     	/* vmode */
137     };
138     
139     static struct fb_fix_screeninfo hga_fix = {
140     	id:		"HGA",
141     	smem_start:	(unsigned long) NULL,
142     	smem_len:	0,
143     	type:		FB_TYPE_PACKED_PIXELS,	/* (not sure) */
144     	type_aux:	0,			/* (not sure) */
145     	visual:		FB_VISUAL_MONO10,
146     	xpanstep:	8,
147     	ypanstep:	8,
148     	ywrapstep:	0,
149     	line_length:	90,
150     	mmio_start:	0,
151     	mmio_len:	0,
152     	accel:		FB_ACCEL_NONE
153     };
154     
155     static struct fb_info fb_info;
156     static struct display disp;
157     
158     /* Don't assume that tty1 will be the initial current console. */
159     static int currcon = -1; 
160     static int release_io_port = 0;
161     static int release_io_ports = 0;
162     
163     #ifdef MODULE
164     static char *font = NULL;
165     static int nologo = 0;
166     #endif
167     
168     /* -------------------------------------------------------------------------
169      *
170      * Low level hardware functions
171      *
172      * ------------------------------------------------------------------------- */
173     
174     static void write_hga_b(unsigned int val, unsigned char reg)
175     {
176     	outb_p(reg, HGA_INDEX_PORT); 
177     	outb_p(val, HGA_VALUE_PORT);
178     }
179     
180     static void write_hga_w(unsigned int val, unsigned char reg)
181     {
182     	outb_p(reg,   HGA_INDEX_PORT); outb_p(val >> 8,   HGA_VALUE_PORT);
183     	outb_p(reg+1, HGA_INDEX_PORT); outb_p(val & 0xff, HGA_VALUE_PORT);
184     }
185     
186     static int test_hga_b(unsigned char val, unsigned char reg)
187     {
188     	outb_p(reg, HGA_INDEX_PORT); 
189     	outb  (val, HGA_VALUE_PORT);
190     	udelay(20); val = (inb_p(HGA_VALUE_PORT) == val);
191     	return val;
192     }
193     
194     static void hga_clear_screen(void)
195     {
196     	unsigned char fillchar = 0xbf; /* magic */
197     	unsigned long flags;
198     
199     	spin_lock_irqsave(&hga_reg_lock, flags);
200     	if (hga_mode == HGA_TXT)
201     		fillchar = ' ';
202     	else if (hga_mode == HGA_GFX)
203     		fillchar = 0x00;
204     	spin_unlock_irqrestore(&hga_reg_lock, flags);
205     	if (fillchar != 0xbf)
206     		memset((char *)hga_vram_base, fillchar, hga_vram_len);
207     }
208     
209     
210     #ifdef MODULE
211     static void hga_txt_mode(void)
212     {
213     	unsigned long flags;
214     
215     	spin_lock_irqsave(&hga_reg_lock, flags);
216     	outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_BLINK_EN, HGA_MODE_PORT);
217     	outb_p(0x00, HGA_GFX_PORT);
218     	outb_p(0x00, HGA_STATUS_PORT);
219     
220     	write_hga_b(0x61, 0x00);	/* horizontal total */
221     	write_hga_b(0x50, 0x01);	/* horizontal displayed */
222     	write_hga_b(0x52, 0x02);	/* horizontal sync pos */
223     	write_hga_b(0x0f, 0x03);	/* horizontal sync width */
224     
225     	write_hga_b(0x19, 0x04);	/* vertical total */
226     	write_hga_b(0x06, 0x05);	/* vertical total adjust */
227     	write_hga_b(0x19, 0x06);	/* vertical displayed */
228     	write_hga_b(0x19, 0x07);	/* vertical sync pos */
229     
230     	write_hga_b(0x02, 0x08);	/* interlace mode */
231     	write_hga_b(0x0d, 0x09);	/* maximum scanline */
232     	write_hga_b(0x0c, 0x0a);	/* cursor start */
233     	write_hga_b(0x0d, 0x0b);	/* cursor end */
234     
235     	write_hga_w(0x0000, 0x0c);	/* start address */
236     	write_hga_w(0x0000, 0x0e);	/* cursor location */
237     
238     	hga_mode = HGA_TXT;
239     	spin_unlock_irqrestore(&hga_reg_lock, flags);
240     }
241     #endif /* MODULE */
242     
243     static void hga_gfx_mode(void)
244     {
245     	unsigned long flags;
246     
247     	spin_lock_irqsave(&hga_reg_lock, flags);
248     	outb_p(0x00, HGA_STATUS_PORT);
249     	outb_p(HGA_GFX_MODE_EN, HGA_GFX_PORT);
250     	outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
251     
252     	write_hga_b(0x35, 0x00);	/* horizontal total */
253     	write_hga_b(0x2d, 0x01);	/* horizontal displayed */
254     	write_hga_b(0x2e, 0x02);	/* horizontal sync pos */
255     	write_hga_b(0x07, 0x03);	/* horizontal sync width */
256     
257     	write_hga_b(0x5b, 0x04);	/* vertical total */
258     	write_hga_b(0x02, 0x05);	/* vertical total adjust */
259     	write_hga_b(0x57, 0x06);	/* vertical displayed */
260     	write_hga_b(0x57, 0x07);	/* vertical sync pos */
261     
262     	write_hga_b(0x02, 0x08);	/* interlace mode */
263     	write_hga_b(0x03, 0x09);	/* maximum scanline */
264     	write_hga_b(0x00, 0x0a);	/* cursor start */
265     	write_hga_b(0x00, 0x0b);	/* cursor end */
266     
267     	write_hga_w(0x0000, 0x0c);	/* start address */
268     	write_hga_w(0x0000, 0x0e);	/* cursor location */
269     
270     	hga_mode = HGA_GFX;
271     	spin_unlock_irqrestore(&hga_reg_lock, flags);
272     }
273     
274     #ifdef MODULE
275     static void hga_show_logo(void)
276     {
277     	int x, y;
278     	char *dest = (char *)hga_vram_base;
279     	char *logo = linux_logo_bw;
280     	for (y = 134; y < 134 + 80 ; y++) /* this needs some cleanup */
281     		for (x = 0; x < 10 ; x++)
282     			*(dest + (y%4)*8192 + (y>>2)*90 + x + 40) = ~*(logo++);
283     }
284     #endif /* MODULE */	
285     
286     static void hga_pan(unsigned int xoffset, unsigned int yoffset)
287     {
288     	unsigned int base;
289     	unsigned long flags;
290     	
291     	base = (yoffset / 8) * 90 + xoffset;
292     	spin_lock_irqsave(&hga_reg_lock, flags);
293     	write_hga_w(base, 0x0c);	/* start address */
294     	spin_unlock_irqrestore(&hga_reg_lock, flags);
295     	DPRINTK("hga_pan: base:%d\n", base);
296     }
297     
298     static void hga_blank(int blank_mode)
299     {
300     	unsigned long flags;
301     
302     	spin_lock_irqsave(&hga_reg_lock, flags);
303     	if (blank_mode) {
304     		outb_p(0x00, HGA_MODE_PORT);	/* disable video */
305     	} else {
306     		outb_p(HGA_MODE_VIDEO_EN | HGA_MODE_GRAPHICS, HGA_MODE_PORT);
307     	}
308     	spin_unlock_irqrestore(&hga_reg_lock, flags);
309     }
310     
311     static int __init hga_card_detect(void)
312     {
313     	int count=0;
314     	u16 *p, p_save;
315     	u16 *q, q_save;
316     
317     	hga_vram_base = VGA_MAP_MEM(0xb0000);
318     	hga_vram_len  = 0x08000;
319     
320     	if (request_region(0x3b0, 12, "hgafb"))
321     		release_io_ports = 1;
322     	if (request_region(0x3bf, 1, "hgafb"))
323     		release_io_port = 1;
324     
325     	/* do a memory check */
326     
327     	p = (u16 *) hga_vram_base;
328     	q = (u16 *) (hga_vram_base + 0x01000);
329     
330     	p_save = scr_readw(p); q_save = scr_readw(q);
331     
332     	scr_writew(0xaa55, p); if (scr_readw(p) == 0xaa55) count++;
333     	scr_writew(0x55aa, p); if (scr_readw(p) == 0x55aa) count++;
334     	scr_writew(p_save, p);
335     
336     	if (count != 2) {
337     		return 0;
338     	}
339     
340     	/* Ok, there is definitely a card registering at the correct
341     	 * memory location, so now we do an I/O port test.
342     	 */
343     	
344     	if (!test_hga_b(0x66, 0x0f)) {	    /* cursor low register */
345     		return 0;
346     	}
347     	if (!test_hga_b(0x99, 0x0f)) {     /* cursor low register */
348     		return 0;
349     	}
350     
351     	/* See if the card is a Hercules, by checking whether the vsync
352     	 * bit of the status register is changing.  This test lasts for
353     	 * approximately 1/10th of a second.
354     	 */
355     	
356     	p_save = q_save = inb_p(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
357     
358     	for (count=0; count < 50000 && p_save == q_save; count++) {
359     		q_save = inb(HGA_STATUS_PORT) & HGA_STATUS_VSYNC;
360     		udelay(2);
361     	}
362     
363     	if (p_save == q_save) 
364     		return 0;
365     
366     	switch (inb_p(HGA_STATUS_PORT) & 0x70) {
367     		case 0x10:
368     			hga_type = TYPE_HERCPLUS;
369     			hga_type_name = "HerculesPlus";
370     			break;
371     		case 0x50:
372     			hga_type = TYPE_HERCCOLOR;
373     			hga_type_name = "HerculesColor";
374     			break;
375     		default:
376     			hga_type = TYPE_HERC;
377     			hga_type_name = "Hercules";
378     			break;
379     	}
380     	return 1;
381     }
382     
383     /* ------------------------------------------------------------------------- *
384      *
385      * dispsw functions
386      *
387      * ------------------------------------------------------------------------- */
388     
389     /**
390      *	hga_get_fix - get the fixed part of the display
391      *	@fix:struct fb_fix_screeninfo to fill in
392      *	@con:unused
393      *	@info:pointer to fb_info object containing info for current hga board
394      *
395      *	This wrapper function copies @info->fix to @fix.
396      *	A zero is returned on success and %-EINVAL for failure.
397      */
398     
399     int hga_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
400     {
401     	CHKINFO(-EINVAL);
402     	DPRINTK("hga_get_fix: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
403     
404     	*fix = info->fix;
405     	return 0;
406     }
407     
408     /**
409      *	hga_get_var - get the user defined part of the display
410      *	@var:struct fb_var_screeninfo to fill in
411      *	@con:unused
412      *	@info:pointer to fb_info object containing info for current hga board
413      *
414      *	This wrapper function copies @info->var to @var.
415      *	A zero is returned on success and %-EINVAL for failure.
416      */
417     
418     int hga_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
419     {
420     	CHKINFO(-EINVAL);
421     	DPRINTK("hga_get_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
422     
423     	*var = info->var;
424     	return 0;
425     }
426     
427     /**
428      *	hga_set_var - set the user defined part of the display
429      *	@var:new video mode
430      *	@con:unused
431      *	@info:pointer to fb_info object containing info for current hga board
432      *	
433      *	This function is called for changing video modes. Since HGA cards have
434      *	only one fixed mode we have not much to do. After checking input 
435      *	parameters @var is copied to @info->var and @info->changevar is called.
436      *	A zero is returned on success and %-EINVAL for failure.
437      *	
438      *	FIXME:
439      *	This is the most mystical function (at least for me).
440      *	What is the exact specification of xxx_set_var()?
441      *	Should it handle xoffset, yoffset? Should it do panning?
442      *	What does vmode mean?
443      */
444     
445     int hga_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
446     {
447     	CHKINFO(-EINVAL);
448     	DPRINTK("hga_set_var: con:%d, activate:%x, info:0x%x, fb_info:%x\n", con, var->activate, (unsigned)info, (unsigned)&fb_info);
449     	
450     	if (var->xres != 720 ||	var->yres != 348 ||
451     	    var->xres_virtual != 720 ||
452     	    var->yres_virtual < 348 || var->yres_virtual > 348 + 16 ||
453     	    var->bits_per_pixel != 1 || var->grayscale != 0) {
454     		return -EINVAL;
455     	}
456     	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
457     		info->var = *var;
458     		if (info->changevar) 
459     			(*info->changevar)(con);
460     	}
461     	return 0;
462     }
463     
464     /**
465      *	hga_getcolreg - read color registers
466      *	@regno:register index to read out
467      *	@red:red value
468      *	@green:green value
469      *	@blue:blue value
470      *	@transp:transparency value
471      *	@info:unused
472      *
473      *	This callback function is used to read the color registers of a HGA
474      *	board. Since we have only two fixed colors, RGB values are 0x0000 
475      *	for register0 and 0xaaaa for register1.
476      *	A zero is returned on success and 1 for failure.
477      */
478     
479     static int hga_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
480     			 u_int *transp, struct fb_info *info)
481     {
482     	if (regno == 0) {
483     		*red = *green = *blue = 0x0000;
484     		*transp = 0;
485     	} else if (regno == 1) {
486     		*red = *green = *blue = 0xaaaa;
487     		*transp = 0;
488     	} else
489     		return 1;
490     	return 0;
491     }
492     
493     /**
494      *	hga_get_cmap - get the colormap
495      *	@cmap:struct fb_cmap to fill in
496      *	@kspc:called from kernel space?
497      *	@con:unused
498      *	@info:pointer to fb_info object containing info for current hga board
499      *
500      *	This wrapper function passes it's input parameters to fb_get_cmap().
501      *	Callback function hga_getcolreg() is used to read the color registers.
502      */
503     
504     int hga_get_cmap(struct fb_cmap *cmap, int kspc, int con,
505                      struct fb_info *info)
506     {
507     	CHKINFO(-EINVAL);
508     	DPRINTK("hga_get_cmap: con:%d\n", con);
509     	return fb_get_cmap(cmap, kspc, hga_getcolreg, info);
510     }
511     	
512     /**
513      *	hga_setcolreg - set color registers
514      *	@regno:register index to set
515      *	@red:red value, unused
516      *	@green:green value, unused
517      *	@blue:blue value, unused
518      *	@transp:transparency value, unused
519      *	@info:unused
520      *
521      *	This callback function is used to set the color registers of a HGA
522      *	board. Since we have only two fixed colors only @regno is checked.
523      *	A zero is returned on success and 1 for failure.
524      */
525     
526     static int hga_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
527     			 u_int transp, struct fb_info *info)
528     {
529     	if (regno > 1)
530     		return 1;
531     	return 0;
532     }
533     
534     /**
535      *	hga_set_cmap - set the colormap
536      *	@cmap:struct fb_cmap to set
537      *	@kspc:called from kernel space?
538      *	@con:unused
539      *	@info:pointer to fb_info object containing info for current hga board
540      *
541      *	This wrapper function passes it's input parameters to fb_set_cmap().
542      *	Callback function hga_setcolreg() is used to set the color registers.
543      */
544     
545     int hga_set_cmap(struct fb_cmap *cmap, int kspc, int con,
546                      struct fb_info *info)
547     {
548     	CHKINFO(-EINVAL);
549     	DPRINTK("hga_set_cmap: con:%d\n", con);
550     	return fb_set_cmap(cmap, kspc, hga_setcolreg, info);
551     }
552     
553     /**
554      *	hga_pan_display - pan or wrap the display
555      *	@var:contains new xoffset, yoffset and vmode values
556      *	@con:unused
557      *	@info:pointer to fb_info object containing info for current hga board
558      *
559      *	This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP
560      *	flag in @var. If input parameters are correct it calls hga_pan() to 
561      *	program the hardware. @info->var is updated to the new values.
562      *	A zero is returned on success and %-EINVAL for failure.
563      */
564     
565     int hga_pan_display(struct fb_var_screeninfo *var, int con,
566                         struct fb_info *info)
567     {
568     	CHKINFO(-EINVAL);
569     	DPRINTK("pan_disp: con:%d, wrap:%d, xoff:%d, yoff:%d\n", con, var->vmode & FB_VMODE_YWRAP, var->xoffset, var->yoffset);
570     
571     	if (var->vmode & FB_VMODE_YWRAP) {
572     		if (var->yoffset < 0 || 
573     		    var->yoffset >= info->var.yres_virtual ||
574     		    var->xoffset)
575     			return -EINVAL;
576     	} else {
577     		if (var->xoffset + var->xres > info->var.xres_virtual
578     		 || var->yoffset + var->yres > info->var.yres_virtual
579     		 || var->yoffset % 8)
580     			return -EINVAL;
581     	}
582     
583     	hga_pan(var->xoffset, var->yoffset);
584     
585     	info->var.xoffset = var->xoffset;
586     	info->var.yoffset = var->yoffset;
587     	if (var->vmode & FB_VMODE_YWRAP)
588     		info->var.vmode |= FB_VMODE_YWRAP;
589     	else
590     		info->var.vmode &= ~FB_VMODE_YWRAP;
591     	return 0;
592     }
593     
594         
595     static struct fb_ops hgafb_ops = {
596     	owner:		THIS_MODULE,
597     	fb_get_fix:	hga_get_fix,
598     	fb_get_var:	hga_get_var,
599     	fb_set_var:	hga_set_var,
600     	fb_get_cmap:	hga_get_cmap,
601     	fb_set_cmap:	hga_set_cmap,
602     	fb_pan_display:	hga_pan_display,
603     };
604     		
605     
606     /* ------------------------------------------------------------------------- *
607      *
608      * Functions in fb_info
609      * 
610      * ------------------------------------------------------------------------- */
611     
612     /**
613      *	hgafbcon_switch - switch console
614      *	@con:new console to switch to
615      *	@info:pointer to fb_info object containing info for current hga board
616      *
617      *	This function should install a new colormap and change the video mode.
618      *	Since we have fixed colors and only one video mode we have nothing to 
619      *	do.
620      *	Only console administration is done but it should go to fbcon.c IMHO.
621      *	A zero is returned on success and %-EINVAL for failure.
622      */
623     
624     static int hgafbcon_switch(int con, struct fb_info *info)
625     {
626     	CHKINFO(-EINVAL);
627     	DPRINTK("hgafbcon_switch: currcon:%d, con:%d, info:%x, fb_info:%x\n", currcon, con, (unsigned)info, (unsigned)&fb_info);
628     
629     	/* Save the colormap and video mode */
630     #if 0	/* Not necessary in hgafb, we use fixed colormap */
631     	fb_copy_cmap(&info->cmap, &fb_display[currcon].cmap, 0);
632     #endif
633     
634     	if (currcon != -1) /* this check is absolute necessary! */
635     		memcpy(&fb_display[currcon].var, &info->var,
636     				sizeof(struct fb_var_screeninfo));
637     
638     	/* Install a new colormap and change the video mode. By default fbcon
639     	 * sets all the colormaps and video modes to the default values at
640     	 * bootup.
641     	 */
642     #if 0
643     	fb_copy_cmap(&fb_display[con].cmap, &info->cmap, 0);
644     	fb_set_cmap(&info->cmap, 1, hga_setcolreg, info);
645     #endif
646     
647     	memcpy(&info->var, &fb_display[con].var,
648     			sizeof(struct fb_var_screeninfo));
649     	/* hga_set_var(&info->var, con, &fb_info); is it necessary? */
650     	currcon = con;
651     
652     	/* Hack to work correctly with XF86_Mono */
653     	hga_gfx_mode();
654     	return 0;
655     }
656     
657     /**
658      *	hgafbcon_updatevar - update the user defined part of the display
659      *	@con:console to update or -1 when no consoles defined on this fb
660      *	@info:pointer to fb_info object containing info for current hga board
661      *
662      *	This function is called when @var is changed by fbcon.c without calling 
663      *	hga_set_var(). It usually means scrolling.  hga_pan_display() is called
664      *	to update the hardware and @info->var.
665      *	A zero is returned on success and %-EINVAL for failure.
666      */
667     
668     static int hgafbcon_updatevar(int con, struct fb_info *info)
669     {
670     	CHKINFO(-EINVAL);
671     	DPRINTK("hga_update_var: con:%d, info:%x, fb_info:%x\n", con, (unsigned)info, (unsigned)&fb_info);
672     	return (con < 0) ? -EINVAL : hga_pan_display(&fb_display[con].var, con, info);
673     }
674     
675     /**
676      *	hgafbcon_blank - (un)blank the screen
677      *	@blank_mode:blanking method to use
678      *	@info:unused
679      *	
680      *	Blank the screen if blank_mode != 0, else unblank. 
681      *	Implements VESA suspend and powerdown modes on hardware that supports 
682      *	disabling hsync/vsync:
683      *		@blank_mode == 2 means suspend vsync,
684      *		@blank_mode == 3 means suspend hsync,
685      *		@blank_mode == 4 means powerdown.
686      */
687     
688     static void hgafbcon_blank(int blank_mode, struct fb_info *info)
689     {
690     	CHKINFO( );
691     	DPRINTK("hga_blank: blank_mode:%d, info:%x, fb_info:%x\n", blank_mode, (unsigned)info, (unsigned)&fb_info);
692     
693     	hga_blank(blank_mode);
694     }
695     
696     
697     /* ------------------------------------------------------------------------- */
698         
699     	/*
700     	 *  Initialization
701     	 */
702     
703     int __init hgafb_init(void)
704     {
705     	if (! hga_card_detect()) {
706     		printk(KERN_ERR "hgafb: HGA card not detected.\n");
707     		return -EINVAL;
708     	}
709     
710     	printk(KERN_INFO "hgafb: %s with %ldK of memory detected.\n",
711     		hga_type_name, hga_vram_len/1024);
712     
713     	hga_gfx_mode();
714     	hga_clear_screen();
715     #ifdef MODULE
716     	if (!nologo) hga_show_logo();
717     #endif /* MODULE */
718     
719     	hga_fix.smem_start = hga_vram_base;
720     	hga_fix.smem_len = hga_vram_len;
721     
722     	disp.var = hga_default_var;
723     /*	disp.cmap = ???; */
724     	disp.screen_base = (char*)hga_fix.smem_start;
725     	disp.visual = hga_fix.visual;
726     	disp.type = hga_fix.type;
727     	disp.type_aux = hga_fix.type_aux;
728     	disp.ypanstep = hga_fix.ypanstep;
729     	disp.ywrapstep = hga_fix.ywrapstep;
730     	disp.line_length = hga_fix.line_length;
731     	disp.can_soft_blank = 1;
732     	disp.inverse = 0;
733     #ifdef FBCON_HAS_HGA
734     	disp.dispsw = &fbcon_hga;
735     #else
736     #warning HGAFB will not work as a console!
737     	disp.dispsw = &fbcon_dummy;
738     #endif
739     	disp.dispsw_data = NULL;
740     
741     	disp.scrollmode = SCROLL_YREDRAW;
742     	
743     	strcpy (fb_info.modename, hga_fix.id);
744     	fb_info.node = -1;
745     	fb_info.flags = FBINFO_FLAG_DEFAULT;
746     /*	fb_info.open = ??? */
747     	fb_info.var = hga_default_var;
748     	fb_info.fix = hga_fix;
749     	fb_info.monspecs.hfmin = 0;
750     	fb_info.monspecs.hfmax = 0;
751     	fb_info.monspecs.vfmin = 10000;
752     	fb_info.monspecs.vfmax = 10000;
753     	fb_info.monspecs.dpms = 0;
754     	fb_info.fbops = &hgafb_ops;
755     	fb_info.screen_base = (char *)hga_fix.smem_start;
756     	fb_info.disp = &disp;
757     /*	fb_info.display_fg = ??? */
758     /*	fb_info.fontname initialized later */
759     	fb_info.changevar = NULL;
760     	fb_info.switch_con = hgafbcon_switch;
761     	fb_info.updatevar = hgafbcon_updatevar;
762     	fb_info.blank = hgafbcon_blank;
763     	fb_info.pseudo_palette = NULL; /* ??? */
764     	fb_info.par = NULL;
765     
766             if (register_framebuffer(&fb_info) < 0)
767                     return -EINVAL;
768     
769             printk(KERN_INFO "fb%d: %s frame buffer device\n",
770                    GET_FB_IDX(fb_info.node), fb_info.modename);
771     	
772     	return 0;
773     }
774     
775     	/*
776     	 *  Setup
777     	 */
778     
779     #ifndef MODULE
780     int __init hgafb_setup(char *options)
781     {
782     	/* 
783     	 * Parse user speficied options
784     	 * `video=hga:font:VGA8x16' or
785     	 * `video=hga:font:SUN8x16' recommended
786     	 * Other supported fonts: VGA8x8, Acorn8x8, PEARL8x8
787     	 * More different fonts can be used with the `setfont' utility.
788     	 */
789     
790     	char *this_opt;
791     
792     	fb_info.fontname[0] = '\0';
793     
794     	if (!options || !*options)
795     		return 0;
796     
797     	for (this_opt = strtok(options, ","); this_opt;
798     			this_opt = strtok(NULL, ",")) {
799     		if (!strncmp(this_opt, "font:", 5))
800     			strcpy(fb_info.fontname, this_opt+5);
801     	}
802     	return 0;
803     }
804     #endif /* !MODULE */
805     
806     
807     	/*
808     	 * Cleanup
809     	 */
810     
811     #ifdef MODULE
812     static void hgafb_cleanup(struct fb_info *info)
813     {
814     	hga_txt_mode();
815     	hga_clear_screen();
816     	unregister_framebuffer(info);
817     	if (release_io_ports) release_region(0x3b0, 12);
818     	if (release_io_port) release_region(0x3bf, 1);
819     }
820     #endif /* MODULE */
821     
822     
823     
824     /* -------------------------------------------------------------------------
825      *
826      *  Modularization
827      *
828      * ------------------------------------------------------------------------- */
829     
830     #ifdef MODULE
831     int init_module(void)
832     {
833     	if (font)
834     		strncpy(fb_info.fontname, font, sizeof(fb_info.fontname)-1);
835     	else
836     		fb_info.fontname[0] = '\0';
837     
838     	return hgafb_init();
839     }
840     
841     void cleanup_module(void)
842     {
843     	hgafb_cleanup(&fb_info);
844     }
845     
846     MODULE_AUTHOR("Ferenc Bakonyi (fero@drama.obuda.kando.hu)");
847     MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor");
848     MODULE_LICENSE("GPL");
849     
850     MODULE_PARM(font, "s");
851     MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (VGA8x8, VGA8x16, SUN8x16, Acorn8x8, PEARL8x8) (default=none)");
852     MODULE_PARM(nologo, "i");
853     MODULE_PARM_DESC(nologo, "Disables startup logo if != 0 (default=0)");
854     
855     #endif /* MODULE */
856