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
33struct 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
51struct 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
66static struct xxxfb_info fb_info;
67static struct xxxfb_par current_par;
68static int current_par_valid = 0;
69static struct display disp;
70
71static struct fb_var_screeninfo default_var;
72
73static int currcon = 0;
74static int inverse = 0;
75
76int xxxfb_init(void);
77int xxxfb_setup(char*);
78
79/* ------------------- chipset specific functions -------------------------- */
80
81
82static 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
96static 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
108static 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
129static 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
141static 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
154static 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
165static 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
179static 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
215static 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
228static 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
245static 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
288struct 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
303int __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
336void 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
352int __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 */
366static 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 */
372static 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
383static 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
405MODULE_LICENSE("GPL");
406int init_module(void)
407{
408    return xxxfb_init();
409}
410
411void cleanup_module(void)
412{
413    xxxfb_cleanup(void);
414}
415#endif /* MODULE */
416