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