2 * linux/drivers/video/fbgen.c -- Generic routines for frame buffer devices
4 * Created 3 Jan 1998 by Geert Uytterhoeven
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file README.legal in the main directory of this archive
11 #include <linux/module.h>
12 #include <linux/string.h>
13 #include <linux/tty.h>
15 #include <linux/slab.h>
17 #include <asm/uaccess.h>
21 static int currcon
= 0;
24 /* ---- `Generic' versions of the frame buffer device operations ----------- */
28 * Get the Fixed Part of the Display
31 int fbgen_get_fix(struct fb_fix_screeninfo
*fix
, int con
, struct fb_info
*info
)
33 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
34 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
35 char par
[info2
->parsize
];
38 fbhw
->get_par(&par
, info2
);
42 if ((err
= fbhw
->decode_var(&fb_display
[con
].var
, &par
, info2
)))
45 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
46 return fbhw
->encode_fix(fix
, &par
, info2
);
51 * Get the User Defined Part of the Display
54 int fbgen_get_var(struct fb_var_screeninfo
*var
, int con
, struct fb_info
*info
)
56 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
57 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
58 char par
[info2
->parsize
];
61 fbhw
->get_par(&par
, info2
);
62 fbhw
->encode_var(var
, &par
, info2
);
64 *var
= fb_display
[con
].var
;
70 * Set the User Defined Part of the Display
73 int fbgen_set_var(struct fb_var_screeninfo
*var
, int con
, struct fb_info
*info
)
75 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
77 int oldxres
, oldyres
, oldbpp
, oldxres_virtual
, oldyres_virtual
, oldyoffset
;
79 if ((err
= fbgen_do_set_var(var
, con
== currcon
, info2
)))
81 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
82 oldxres
= fb_display
[con
].var
.xres
;
83 oldyres
= fb_display
[con
].var
.yres
;
84 oldxres_virtual
= fb_display
[con
].var
.xres_virtual
;
85 oldyres_virtual
= fb_display
[con
].var
.yres_virtual
;
86 oldbpp
= fb_display
[con
].var
.bits_per_pixel
;
87 oldyoffset
= fb_display
[con
].var
.yoffset
;
88 fb_display
[con
].var
= *var
;
89 if (oldxres
!= var
->xres
|| oldyres
!= var
->yres
||
90 oldxres_virtual
!= var
->xres_virtual
||
91 oldyres_virtual
!= var
->yres_virtual
||
92 oldbpp
!= var
->bits_per_pixel
||
93 oldyoffset
!= var
->yoffset
) {
94 fbgen_set_disp(con
, info2
);
96 (*info
->changevar
)(con
);
97 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
, 0, 0)))
99 fbgen_install_cmap(con
, info2
);
111 int fbgen_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
112 struct fb_info
*info
)
114 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
115 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
117 if (con
== currcon
) /* current console ? */
118 return fb_get_cmap(cmap
, kspc
, fbhw
->getcolreg
, info
);
120 if (fb_display
[con
].cmap
.len
) /* non default colormap ? */
121 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
123 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 64 : 256;
124 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
134 int fbgen_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
135 struct fb_info
*info
)
137 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
138 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
141 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated ? */
142 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 64 : 256;
143 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
, size
, 0)))
146 if (con
== currcon
) /* current console ? */
147 return fb_set_cmap(cmap
, kspc
, fbhw
->setcolreg
, info
);
149 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
155 * Pan or Wrap the Display
157 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
160 int fbgen_pan_display(struct fb_var_screeninfo
*var
, int con
,
161 struct fb_info
*info
)
163 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
164 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
165 int xoffset
= var
->xoffset
;
166 int yoffset
= var
->yoffset
;
170 xoffset
+fb_display
[con
].var
.xres
> fb_display
[con
].var
.xres_virtual
||
172 yoffset
+fb_display
[con
].var
.yres
> fb_display
[con
].var
.yres_virtual
)
174 if (con
== currcon
) {
175 if (fbhw
->pan_display
) {
176 if ((err
= fbhw
->pan_display(var
, info2
)))
181 fb_display
[con
].var
.xoffset
= var
->xoffset
;
182 fb_display
[con
].var
.yoffset
= var
->yoffset
;
183 if (var
->vmode
& FB_VMODE_YWRAP
)
184 fb_display
[con
].var
.vmode
|= FB_VMODE_YWRAP
;
186 fb_display
[con
].var
.vmode
&= ~FB_VMODE_YWRAP
;
193 * Frame Buffer Specific ioctls
196 int fbgen_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
197 unsigned long arg
, int con
, struct fb_info
*info
)
203 /* ---- Helper functions --------------------------------------------------- */
207 * Change the video mode
210 int fbgen_do_set_var(struct fb_var_screeninfo
*var
, int isactive
,
211 struct fb_info_gen
*info
)
213 struct fbgen_hwswitch
*fbhw
= info
->fbhw
;
215 char par
[info
->parsize
];
217 if ((err
= fbhw
->decode_var(var
, &par
, info
)))
219 activate
= var
->activate
;
220 if (((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) && isactive
)
221 fbhw
->set_par(&par
, info
);
222 fbhw
->encode_var(var
, &par
, info
);
223 var
->activate
= activate
;
228 void fbgen_set_disp(int con
, struct fb_info_gen
*info
)
230 struct fbgen_hwswitch
*fbhw
= info
->fbhw
;
231 struct fb_fix_screeninfo fix
;
232 char par
[info
->parsize
];
233 struct display
*display
;
236 display
= &fb_display
[con
];
238 display
= info
->info
.disp
; /* used during initialization */
241 fbhw
->get_par(&par
, info
);
243 fbhw
->decode_var(&fb_display
[con
].var
, &par
, info
);
244 memset(&fix
, 0, sizeof(struct fb_fix_screeninfo
));
245 fbhw
->encode_fix(&fix
, &par
, info
);
247 display
->visual
= fix
.visual
;
248 display
->type
= fix
.type
;
249 display
->type_aux
= fix
.type_aux
;
250 display
->ypanstep
= fix
.ypanstep
;
251 display
->ywrapstep
= fix
.ywrapstep
;
252 display
->line_length
= fix
.line_length
;
253 if (info
->fbhw
->blank
|| fix
.visual
== FB_VISUAL_PSEUDOCOLOR
||
254 fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
255 display
->can_soft_blank
= 1;
257 display
->can_soft_blank
= 0;
258 fbhw
->set_disp(&par
, display
, info
);
259 #if 0 /* FIXME: generic inverse is not supported yet */
260 display
->inverse
= (fix
.visual
== FB_VISUAL_MONO01
? !inverse
: inverse
);
262 display
->inverse
= fix
.visual
== FB_VISUAL_MONO01
;
268 * Install the current colormap
271 void fbgen_install_cmap(int con
, struct fb_info_gen
*info
)
273 struct fbgen_hwswitch
*fbhw
= info
->fbhw
;
276 if (fb_display
[con
].cmap
.len
)
277 fb_set_cmap(&fb_display
[con
].cmap
, 1, fbhw
->setcolreg
, &info
->info
);
279 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 64 : 256;
280 fb_set_cmap(fb_default_cmap(size
), 1, fbhw
->setcolreg
, &info
->info
);
286 * Update the `var' structure (called by fbcon.c)
289 int fbgen_update_var(int con
, struct fb_info
*info
)
291 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
292 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
295 if (fbhw
->pan_display
) {
296 if ((err
= fbhw
->pan_display(&fb_display
[con
].var
, info2
)))
304 * Switch to a different virtual console
307 int fbgen_switch(int con
, struct fb_info
*info
)
309 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
310 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
312 /* Do we have to save the colormap ? */
313 if (fb_display
[currcon
].cmap
.len
)
314 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, fbhw
->getcolreg
,
316 fbgen_do_set_var(&fb_display
[con
].var
, 1, info2
);
318 /* Install new colormap */
319 fbgen_install_cmap(con
, info2
);
328 void fbgen_blank(int blank
, struct fb_info
*info
)
330 struct fb_info_gen
*info2
= (struct fb_info_gen
*)info
;
331 struct fbgen_hwswitch
*fbhw
= info2
->fbhw
;
335 if (fbhw
->blank
&& !fbhw
->blank(blank
, info2
))
338 memset(black
, 0, 16*sizeof(u16
));
345 fb_set_cmap(&cmap
, 1, fbhw
->setcolreg
, info
);
347 fbgen_install_cmap(currcon
, info2
);