This is pre8 ...
[linux-2.6/linux-mips.git] / drivers / video / q40fb.c
blob12175a1f89304224538e7255c0038c481ff9bb1c
1 #include <linux/kernel.h>
2 #include <linux/errno.h>
3 #include <linux/string.h>
4 #include <linux/mm.h>
5 #include <linux/tty.h>
6 #include <linux/malloc.h>
7 #include <linux/delay.h>
8 #include <linux/interrupt.h>
10 #include <asm/uaccess.h>
11 #include <asm/setup.h>
12 #include <asm/segment.h>
13 #include <asm/system.h>
14 /*#include <asm/irq.h>*/
15 #include <asm/q40_master.h>
16 #include <linux/fb.h>
17 #include <linux/module.h>
18 #include <asm/pgtable.h>
20 #include <video/fbcon.h>
21 #include <video/fbcon-cfb16.h>
23 #define FBIOSETSCROLLMODE 0x4611
25 #define Q40_PHYS_SCREEN_ADDR 0xFE800000
26 static unsigned long q40_screen_addr;
28 static u16 fbcon_cmap_cfb16[16];
30 /* frame buffer operations */
32 static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
33 struct fb_info *info);
34 static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
35 struct fb_info *info);
36 static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
37 struct fb_info *info);
38 static int q40fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
39 struct fb_info *info);
40 static int q40fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
41 struct fb_info *info);
42 static int q40fb_pan_display(struct fb_var_screeninfo *var, int con,
43 struct fb_info *info);
44 static int q40fb_ioctl(struct inode *inode, struct file *file,
45 unsigned int cmd, unsigned long arg, int con,
46 struct fb_info *info);
48 static int q40con_switch(int con, struct fb_info *info);
49 static int q40con_updatevar(int con, struct fb_info *info);
50 static void q40con_blank(int blank, struct fb_info *info);
52 static void q40fb_set_disp(int con, struct fb_info *info);
54 static struct display disp[MAX_NR_CONSOLES];
55 static struct fb_info fb_info;
56 static struct fb_ops q40fb_ops = {
57 owner: THIS_MODULE,
58 fb_get_fix: q40fb_get_fix,
59 fb_get_var: q40fb_get_var,
60 fb_set_var: q40fb_set_var,
61 fb_get_cmap: q40fb_get_cmap,
62 fb_set_cmap: q40fb_set_cmap,
63 fb_pan_display: q40fb_pan_display,
64 fb_ioctl: q40fb_ioctl,
67 static int currcon=0;
69 static char q40fb_name[]="Q40";
71 static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
72 struct fb_info *info)
74 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
76 strcpy(fix->id,"Q40");
77 fix->smem_start=q40_screen_addr;
78 fix->smem_len=1024*1024;
79 fix->type=FB_TYPE_PACKED_PIXELS;
80 fix->type_aux=0;
81 fix->visual=FB_VISUAL_TRUECOLOR; /* good approximation so far ..*/;
82 fix->xpanstep=0;
83 fix->ypanstep=0;
84 fix->ywrapstep=0;
85 fix->line_length=1024*2;
87 /* no mmio,accel ...*/
89 return 0;
93 static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
94 struct fb_info *info)
96 memset(var, 0, sizeof(struct fb_var_screeninfo));
98 var->xres=1024;
99 var->yres=512;
100 var->xres_virtual=1024;
101 var->yres_virtual=512;
102 var->xoffset=0;
103 var->yoffset=0;
104 var->bits_per_pixel=16;
105 var->grayscale=0;
106 var->nonstd=0;
107 var->activate=FB_ACTIVATE_NOW;
108 var->height=230; /* approx for my 17" monitor, more important */
109 var->width=300; /* than the absolute values is the unusual aspect ratio*/
111 var->red.offset=6; /*6*/
112 var->red.length=5;
113 var->green.offset=11; /*11*/
114 var->green.length=5;
115 var->blue.offset=0;
116 var->blue.length=6;
117 var->transp.length=0;
119 var->pixclock=0;
120 var->left_margin=0;
121 var->right_margin=0;
122 var->hsync_len=0;
123 var->vsync_len=0;
124 var->sync=0;
125 var->vmode=FB_VMODE_NONINTERLACED;
127 return 0;
131 static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
132 struct fb_info *info)
134 if(var->xres!=1024)
135 return -EINVAL;
136 if(var->yres!=512)
137 return -EINVAL;
138 if(var->xres_virtual!=1024)
139 return -EINVAL;
140 if(var->yres_virtual!=512)
141 return -EINVAL;
142 if(var->xoffset!=0)
143 return -EINVAL;
144 if(var->yoffset!=0)
145 return -EINVAL;
146 if(var->bits_per_pixel!=16)
147 return -EINVAL;
148 if(var->grayscale!=0)
149 return -EINVAL;
150 if(var->nonstd!=0)
151 return -EINVAL;
152 if(var->activate!=FB_ACTIVATE_NOW)
153 return -EINVAL;
154 if(var->pixclock!=0)
155 return -EINVAL;
156 if(var->left_margin!=0)
157 return -EINVAL;
158 if(var->right_margin!=0)
159 return -EINVAL;
160 if(var->hsync_len!=0)
161 return -EINVAL;
162 if(var->vsync_len!=0)
163 return -EINVAL;
164 if(var->sync!=0)
165 return -EINVAL;
166 if(var->vmode!=FB_VMODE_NONINTERLACED)
167 return -EINVAL;
169 return 0;
173 static int q40_getcolreg(unsigned regno, unsigned *red, unsigned *green,
174 unsigned *blue, unsigned *transp,
175 struct fb_info *info)
178 * Read a single color register and split it into colors/transparent.
179 * The return values must have a 16 bit magnitude.
180 * Return != 0 for invalid regno.
182 if (regno>=16) return 1;
184 *transp=0;
185 *green = ((fbcon_cmap_cfb16[regno]>>11) & 31)<<11;
186 *red = ((fbcon_cmap_cfb16[regno]>>6) & 31)<<11;
187 *blue = ((fbcon_cmap_cfb16[regno]) & 63)<<10;
189 return 0;
192 static int q40_setcolreg(unsigned regno, unsigned red, unsigned green,
193 unsigned blue, unsigned transp,
194 const struct fb_info *info)
197 * Set a single color register. The values supplied have a 16 bit
198 * magnitude.
199 * Return != 0 for invalid regno.
202 red>>=11;
203 green>>=11;
204 blue>>=10;
206 if (regno < 16) {
207 fbcon_cmap_cfb16[regno] = ((red & 31) <<6) |
208 ((green & 31) << 11) |
209 (blue & 63);
211 return 0;
214 static int q40fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
215 struct fb_info *info)
217 #if 1
218 if (con == currcon) /* current console? */
219 return fb_get_cmap(cmap, kspc, q40_getcolreg, info);
220 else if (fb_display[con].cmap.len) /* non default colormap? */
221 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
222 else
223 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
224 cmap, kspc ? 0 : 2);
225 return 0;
226 #else
227 printk(KERN_ERR "get cmap not supported\n");
229 return -EINVAL;
230 #endif
233 static int q40fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
234 struct fb_info *info)
236 #if 1
237 int err;
239 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
240 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
241 1<<fb_display[con].var.bits_per_pixel,
242 0)))
243 return err;
245 if (con == currcon) /* current console? */
246 return fb_set_cmap(cmap, kspc, q40_setcolreg, info);
247 else
248 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
249 return 0;
250 #else
251 printk(KERN_ERR "set cmap not supported\n");
253 return -EINVAL;
254 #endif
257 static int q40fb_pan_display(struct fb_var_screeninfo *var, int con,
258 struct fb_info *info)
260 printk(KERN_ERR "panning not supported\n");
262 return -EINVAL;
266 static int q40fb_ioctl(struct inode *inode, struct file *file,
267 unsigned int cmd, unsigned long arg, int con,
268 struct fb_info *info)
270 #if 0
271 unsigned long i;
272 struct display *display;
274 if (con>=0)
275 display = &fb_display[con];
276 else
277 display = &disp[0];
279 if (cmd == FBIOSETSCROLLMODE)
281 i = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long));
282 if (!i)
284 copy_from_user(&i, (void *)arg, sizeof(unsigned long));
285 display->scrollmode = i;
287 q40_updatescrollmode(display);
288 return i;
290 #endif
291 return -EINVAL;
294 static void q40fb_set_disp(int con, struct fb_info *info)
296 struct fb_fix_screeninfo fix;
297 struct display *display;
299 q40fb_get_fix(&fix, con, info);
301 if (con>=0)
302 display = &fb_display[con];
303 else
304 display = &disp[0];
306 if (con<0) con=0;
308 display->screen_base = fix.smem_start;
309 display->visual = fix.visual;
310 display->type = fix.type;
311 display->type_aux = fix.type_aux;
312 display->ypanstep = fix.ypanstep;
313 display->ywrapstep = fix.ywrapstep;
314 display->can_soft_blank = 0;
315 display->inverse = 0;
316 display->line_length = fix.line_length;
318 display->scrollmode = SCROLL_YREDRAW;
320 #ifdef FBCON_HAS_CFB16
321 display->dispsw = &fbcon_cfb16;
322 disp->dispsw_data = fbcon_cmap_cfb16;
323 #else
324 display->dispsw = &fbcon_dummy;
325 #endif
328 int q40fb_init(void)
331 if ( !MACH_IS_Q40)
332 return -ENXIO;
333 #if 0
334 q40_screen_addr = kernel_map(Q40_PHYS_SCREEN_ADDR, 1024*1024,
335 KERNELMAP_NO_COPYBACK, NULL);
336 #else
337 q40_screen_addr = Q40_PHYS_SCREEN_ADDR; /* mapped in q40/config.c */
338 #endif
340 fb_info.changevar=NULL;
341 strcpy(&fb_info.modename[0],q40fb_name);
342 fb_info.fontname[0]=0;
343 fb_info.disp=disp;
344 fb_info.switch_con=&q40con_switch;
345 fb_info.updatevar=&q40con_updatevar;
346 fb_info.blank=&q40con_blank;
347 fb_info.node = -1;
348 fb_info.fbops = &q40fb_ops;
349 fb_info.flags = FBINFO_FLAG_DEFAULT; /* not as module for now */
351 master_outb(3,DISPLAY_CONTROL_REG);
353 q40fb_get_var(&disp[0].var, 0, &fb_info);
354 q40fb_set_disp(-1, &fb_info);
356 if (register_framebuffer(&fb_info) < 0) {
357 printk(KERN_ERR "unable to register Q40 frame buffer\n");
358 return -EINVAL;
361 printk(KERN_INFO "fb%d: Q40 frame buffer alive and kicking !\n",
362 GET_FB_IDX(fb_info.node));
363 return 0;
367 static int q40con_switch(int con, struct fb_info *info)
369 currcon=con;
371 return 0;
375 static int q40con_updatevar(int con, struct fb_info *info)
377 return 0;
380 static void q40con_blank(int blank, struct fb_info *info)