1 /*
2 * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
3 *
4 * Created 28 Dec 1997 by Geert Uytterhoeven
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
15 #include <linux/mm.h>
16 #include <linux/tty.h>
17 #include <linux/slab.h>
18 #include <linux/delay.h>
19 #include <linux/fb.h>
20 #include <linux/init.h>
21
22 #include <video/fbcon.h>
23
24
25 /*
26 * This is just simple sample code.
27 *
28 * No warranty that it actually compiles.
29 * Even less warranty that it actually works :-)
30 */
31
32
33 struct xxxfb_info {
34 /*
35 * Choose _one_ of the two alternatives:
36 *
37 * 1. Use the generic frame buffer operations (fbgen_*).
38 */
39 struct fb_info_gen gen;
40 /*
41 * 2. Provide your own frame buffer operations.
42 */
43 struct fb_info info;
44
45 /* Here starts the frame buffer device dependent part */
46 /* You can use this to store e.g. the board number if you support */
47 /* multiple boards */
48 };
49
50
51 struct xxxfb_par {
52 /*
53 * The hardware specific data in this structure uniquely defines a video
54 * mode.
55 *
56 * If your hardware supports only one video mode, you can leave it empty.
57 */
58 };
59
60
61 /*
62 * If your driver supports multiple boards, you should make these arrays,
63 * or allocate them dynamically (using kmalloc()).
64 */
65
66 static struct xxxfb_info fb_info;
67 static struct xxxfb_par current_par;
68 static int current_par_valid = 0;
69 static struct display disp;
70
71 static struct fb_var_screeninfo default_var;
72
73 static int currcon = 0;
74 static int inverse = 0;
75
76 int xxxfb_init(void);
77 int xxxfb_setup(char*);
78
79 /* ------------------- chipset specific functions -------------------------- */
80
81
xxx_detect(void)82 static void xxx_detect(void)
83 {
84 /*
85 * This function should detect the current video mode settings and store
86 * it as the default video mode
87 */
88
89 struct xxxfb_par par;
90
91 /* ... */
92 xxx_get_par(&par);
93 xxx_encode_var(&default_var, &par);
94 }
95
xxx_encode_fix(struct fb_fix_screeninfo * fix,struct xxxfb_par * par,const struct fb_info * info)96 static int xxx_encode_fix(struct fb_fix_screeninfo *fix, struct xxxfb_par *par,
97 const struct fb_info *info)
98 {
99 /*
100 * This function should fill in the 'fix' structure based on the values
101 * in the `par' structure.
102 */
103
104 /* ... */
105 return 0;
106 }
107
xxx_decode_var(struct fb_var_screeninfo * var,struct xxxfb_par * par,const struct fb_info * info)108 static int xxx_decode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par,
109 const struct fb_info *info)
110 {
111 /*
112 * Get the video params out of 'var'. If a value doesn't fit, round it up,
113 * if it's too big, return -EINVAL.
114 *
115 * Suggestion: Round up in the following order: bits_per_pixel, xres,
116 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
117 * bitfields, horizontal timing, vertical timing.
118 */
119
120 /* ... */
121
122 /* pixclock in picos, htotal in pixels, vtotal in scanlines */
123 if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
124 return -EINVAL;
125
126 return 0;
127 }
128
xxx_encode_var(struct fb_var_screeninfo * var,struct xxxfb_par * par,const struct fb_info * info)129 static int xxx_encode_var(struct fb_var_screeninfo *var, struct xxxfb_par *par,
130 const struct fb_info *info)
131 {
132 /*
133 * Fill the 'var' structure based on the values in 'par' and maybe other
134 * values read out of the hardware.
135 */
136
137 /* ... */
138 return 0;
139 }
140
xxx_get_par(struct xxxfb_par * par,const struct fb_info * info)141 static void xxx_get_par(struct xxxfb_par *par, const struct fb_info *info)
142 {
143 /*
144 * Fill the hardware's 'par' structure.
145 */
146
147 if (current_par_valid)
148 *par = current_par;
149 else {
150 /* ... */
151 }
152 }
153
xxx_set_par(struct xxxfb_par * par,const struct fb_info * info)154 static void xxx_set_par(struct xxxfb_par *par, const struct fb_info *info)
155 {
156 /*
157 * Set the hardware according to 'par'.
158 */
159
160 current_par = *par;
161 current_par_valid = 1;
162 /* ... */
163 }
164
xxx_getcolreg(unsigned regno,unsigned * red,unsigned * green,unsigned * blue,unsigned * transp,const struct fb_info * info)165 static int xxx_getcolreg(unsigned regno, unsigned *red, unsigned *green,
166 unsigned *blue, unsigned *transp,
167 const struct fb_info *info)
168 {
169 /*
170 * Read a single color register and split it into colors/transparent.
171 * The return values must have a 16 bit magnitude.
172 * Return != 0 for invalid regno.
173 */
174
175 /* ... */
176 return 0;
177 }
178
xxx_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,const struct fb_info * info)179 static int xxx_setcolreg(unsigned regno, unsigned red, unsigned green,
180 unsigned blue, unsigned transp,
181 const struct fb_info *info)
182 {
183 /*
184 * Set a single color register. The values supplied have a 16 bit
185 * magnitude.
186 * Return != 0 for invalid regno.
187 */
188
189 if (regno < 16) {
190 /*
191 * Make the first 16 colors of the palette available to fbcon
192 */
193 if (is_cfb15) /* RGB 555 */
194 ...fbcon_cmap.cfb16[regno] = ((red & 0xf800) >> 1) |
195 ((green & 0xf800) >> 6) |
196 ((blue & 0xf800) >> 11);
197 if (is_cfb16) /* RGB 565 */
198 ...fbcon_cmap.cfb16[regno] = (red & 0xf800) |
199 ((green & 0xfc00) >> 5) |
200 ((blue & 0xf800) >> 11);
201 if (is_cfb24) /* RGB 888 */
202 ...fbcon_cmap.cfb24[regno] = ((red & 0xff00) << 8) |
203 (green & 0xff00) |
204 ((blue & 0xff00) >> 8);
205 if (is_cfb32) /* RGBA 8888 */
206 ...fbcon_cmap.cfb32[regno] = ((red & 0xff00) << 16) |
207 ((green & 0xff00) << 8) |
208 (blue & 0xff00) |
209 ((transp & 0xff00) >> 8);
210 }
211 /* ... */
212 return 0;
213 }
214
xxx_pan_display(struct fb_var_screeninfo * var,struct xxxfb_par * par,const struct fb_info * info)215 static int xxx_pan_display(struct fb_var_screeninfo *var,
216 struct xxxfb_par *par, const struct fb_info *info)
217 {
218 /*
219 * Pan (or wrap, depending on the `vmode' field) the display using the
220 * `xoffset' and `yoffset' fields of the `var' structure.
221 * If the values don't fit, return -EINVAL.
222 */
223
224 /* ... */
225 return 0;
226 }
227
xxx_blank(int blank_mode,const struct fb_info * info)228 static int xxx_blank(int blank_mode, const struct fb_info *info)
229 {
230 /*
231 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
232 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
233 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
234 * to e.g. a video mode which doesn't support it. Implements VESA suspend
235 * and powerdown modes on hardware that supports disabling hsync/vsync:
236 * blank_mode == 2: suspend vsync
237 * blank_mode == 3: suspend hsync
238 * blank_mode == 4: powerdown
239 */
240
241 /* ... */
242 return 0;
243 }
244
xxx_set_disp(const void * par,struct display * disp,struct fb_info_gen * info)245 static void xxx_set_disp(const void *par, struct display *disp,
246 struct fb_info_gen *info)
247 {
248 /*
249 * Fill in a pointer with the virtual address of the mapped frame buffer.
250 * Fill in a pointer to appropriate low level text console operations (and
251 * optionally a pointer to help data) for the video mode `par' of your
252 * video hardware. These can be generic software routines, or hardware
253 * accelerated routines specifically tailored for your hardware.
254 * If you don't have any appropriate operations, you must fill in a
255 * pointer to dummy operations, and there will be no text output.
256 */
257 disp->screen_base = virtual_frame_buffer_address;
258 #ifdef FBCON_HAS_CFB8
259 if (is_cfb8) {
260 disp->dispsw = fbcon_cfb8;
261 } else
262 #endif
263 #ifdef FBCON_HAS_CFB16
264 if (is_cfb16) {
265 disp->dispsw = fbcon_cfb16;
266 disp->dispsw_data = ...fbcon_cmap.cfb16; /* console palette */
267 } else
268 #endif
269 #ifdef FBCON_HAS_CFB24
270 if (is_cfb24) {
271 disp->dispsw = fbcon_cfb24;
272 disp->dispsw_data = ...fbcon_cmap.cfb24; /* console palette */
273 } else
274 #endif
275 #ifdef FBCON_HAS_CFB32
276 if (is_cfb32) {
277 disp->dispsw = fbcon_cfb32;
278 disp->dispsw_data = ...fbcon_cmap.cfb32; /* console palette */
279 } else
280 #endif
281 disp->dispsw = &fbcon_dummy;
282 }
283
284
285 /* ------------ Interfaces to hardware functions ------------ */
286
287
288 struct fbgen_hwswitch xxx_switch = {
289 xxx_detect, xxx_encode_fix, xxx_decode_var, xxx_encode_var, xxx_get_par,
290 xxx_set_par, xxx_getcolreg, xxx_setcolreg, xxx_pan_display, xxx_blank,
291 xxx_set_disp
292 };
293
294
295
296 /* ------------ Hardware Independent Functions ------------ */
297
298
299 /*
300 * Initialization
301 */
302
xxxfb_init(void)303 int __init xxxfb_init(void)
304 {
305 fb_info.gen.fbhw = &xxx_switch;
306 fb_info.gen.fbhw->detect();
307 strcpy(fb_info.gen.info.modename, "XXX");
308 fb_info.gen.info.changevar = NULL;
309 fb_info.gen.info.node = -1;
310 fb_info.gen.info.fbops = &xxxfb_ops;
311 fb_info.gen.info.disp = &disp;
312 fb_info.gen.info.switch_con = &xxxfb_switch;
313 fb_info.gen.info.updatevar = &xxxfb_update_var;
314 fb_info.gen.info.blank = &xxxfb_blank;
315 fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
316 /* This should give a reasonable default video mode */
317 fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
318 fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
319 fbgen_set_disp(-1, &fb_info.gen);
320 fbgen_install_cmap(0, &fb_info.gen);
321 if (register_framebuffer(&fb_info.gen.info) < 0)
322 return -EINVAL;
323 printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
324 fb_info.gen.info.modename);
325
326 /* uncomment this if your driver cannot be unloaded */
327 /* MOD_INC_USE_COUNT; */
328 return 0;
329 }
330
331
332 /*
333 * Cleanup
334 */
335
xxxfb_cleanup(struct fb_info * info)336 void xxxfb_cleanup(struct fb_info *info)
337 {
338 /*
339 * If your driver supports multiple boards, you should unregister and
340 * clean up all instances.
341 */
342
343 unregister_framebuffer(info);
344 /* ... */
345 }
346
347
348 /*
349 * Setup
350 */
351
xxxfb_setup(char * options)352 int __init xxxfb_setup(char *options)
353 {
354 /* Parse user speficied options (`video=xxxfb:') */
355 }
356
357
358 /* ------------------------------------------------------------------------- */
359
360
361 /*
362 * Frame buffer operations
363 */
364
365 /* If all you need is that - just don't define ->fb_open */
xxxfb_open(const struct fb_info * info,int user)366 static int xxxfb_open(const struct fb_info *info, int user)
367 {
368 return 0;
369 }
370
371 /* If all you need is that - just don't define ->fb_release */
xxxfb_release(const struct fb_info * info,int user)372 static int xxxfb_release(const struct fb_info *info, int user)
373 {
374 return 0;
375 }
376
377
378 /*
379 * In most cases the `generic' routines (fbgen_*) should be satisfactory.
380 * However, you're free to fill in your own replacements.
381 */
382
383 static struct fb_ops xxxfb_ops = {
384 owner: THIS_MODULE,
385 fb_open: xxxfb_open, /* only if you need it to do something */
386 fb_release: xxxfb_release, /* only if you need it to do something */
387 fb_get_fix: fbgen_get_fix,
388 fb_get_var: fbgen_get_var,
389 fb_set_var: fbgen_set_var,
390 fb_get_cmap: fbgen_get_cmap,
391 fb_set_cmap: fbgen_set_cmap,
392 fb_pan_display: fbgen_pan_display,
393 fb_ioctl: xxxfb_ioctl, /* optional */
394 };
395
396
397 /* ------------------------------------------------------------------------- */
398
399
400 /*
401 * Modularization
402 */
403
404 #ifdef MODULE
405 MODULE_LICENSE("GPL");
init_module(void)406 int init_module(void)
407 {
408 return xxxfb_init();
409 }
410
cleanup_module(void)411 void cleanup_module(void)
412 {
413 xxxfb_cleanup(void);
414 }
415 #endif /* MODULE */
416