xref: /minix3/minix/drivers/video/fb/fb.c (revision 3f82ac6a4e188419336747098d0d6616cd2f3d3d)
1433d6423SLionel Sambuc #include <minix/fb.h>
2433d6423SLionel Sambuc #include <minix/chardriver.h>
3433d6423SLionel Sambuc #include <minix/drivers.h>
4433d6423SLionel Sambuc #include <minix/ds.h>
5433d6423SLionel Sambuc #include <minix/sysutil.h>
6433d6423SLionel Sambuc #include <minix/type.h>
7433d6423SLionel Sambuc #include <minix/vm.h>
8433d6423SLionel Sambuc #include <sys/ioc_fb.h>
9433d6423SLionel Sambuc #include <assert.h>
10433d6423SLionel Sambuc #include <sys/ioctl.h>
11433d6423SLionel Sambuc #include <sys/mman.h>
12433d6423SLionel Sambuc #include <stdio.h>
13433d6423SLionel Sambuc #include <stdlib.h>
14433d6423SLionel Sambuc #include <stdint.h>
15433d6423SLionel Sambuc #include <dev/videomode/videomode.h>
16433d6423SLionel Sambuc #include <dev/videomode/edidvar.h>
17433d6423SLionel Sambuc #include <dev/videomode/edidreg.h>
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #include "logos.h"
20433d6423SLionel Sambuc #include "fb_edid.h"
21433d6423SLionel Sambuc #include "fb.h"
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc /*
24433d6423SLionel Sambuc  * Function prototypes for the fb driver.
25433d6423SLionel Sambuc  */
26433d6423SLionel Sambuc static int fb_open(devminor_t minor, int access, endpoint_t user_endpt);
27433d6423SLionel Sambuc static int fb_close(devminor_t minor);
28433d6423SLionel Sambuc static ssize_t fb_read(devminor_t minor, u64_t pos, endpoint_t ep,
29433d6423SLionel Sambuc 	cp_grant_id_t gid, size_t size, int flags, cdev_id_t id);
30433d6423SLionel Sambuc static ssize_t fb_write(devminor_t minor, u64_t pos, endpoint_t ep,
31433d6423SLionel Sambuc 	cp_grant_id_t gid, size_t size, int flags, cdev_id_t id);
32433d6423SLionel Sambuc static int fb_ioctl(devminor_t minor, unsigned long request, endpoint_t ep,
33433d6423SLionel Sambuc 	cp_grant_id_t gid, int flags, endpoint_t user_ep, cdev_id_t id);
34433d6423SLionel Sambuc static void paint_bootlogo(int minor);
35433d6423SLionel Sambuc static void paint_restartlogo(int minor);
36433d6423SLionel Sambuc static void paint_centered(int minor, char *data, int width, int height);
37433d6423SLionel Sambuc static int do_get_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid);
38433d6423SLionel Sambuc static int do_put_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid);
39433d6423SLionel Sambuc static int do_get_fixscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid);
40433d6423SLionel Sambuc static int do_pan_display(int minor, endpoint_t ep, cp_grant_id_t gid);
41433d6423SLionel Sambuc static int keep_displaying_restarted(void);
42433d6423SLionel Sambuc 
43433d6423SLionel Sambuc /* Entry points to the fb driver. */
44433d6423SLionel Sambuc static struct chardriver fb_tab =
45433d6423SLionel Sambuc {
46433d6423SLionel Sambuc 	.cdr_open	= fb_open,
47433d6423SLionel Sambuc 	.cdr_close	= fb_close,
48433d6423SLionel Sambuc 	.cdr_read	= fb_read,
49433d6423SLionel Sambuc 	.cdr_write	= fb_write,
50433d6423SLionel Sambuc 	.cdr_ioctl	= fb_ioctl
51433d6423SLionel Sambuc };
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc /** Represents the /dev/fb device. */
54433d6423SLionel Sambuc static int has_restarted = 0;
55433d6423SLionel Sambuc static u64_t has_restarted_t1, has_restarted_t2;
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc static int open_counter[FB_DEV_NR];		/* Open count */
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc static int
fb_open(devminor_t minor,int UNUSED (access),endpoint_t UNUSED (user_endpt))60433d6423SLionel Sambuc fb_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt))
61433d6423SLionel Sambuc {
62433d6423SLionel Sambuc 	int r;
63433d6423SLionel Sambuc 	static int initialized = 0;
64433d6423SLionel Sambuc 	static struct edid_info info;
65433d6423SLionel Sambuc 	static struct edid_info *infop = NULL;
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc 	if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc 	if (!initialized) {
70433d6423SLionel Sambuc 		r = fb_edid_read(minor, &info);
71433d6423SLionel Sambuc 		infop = (r == 0) ? &info : NULL;
72433d6423SLionel Sambuc 	}
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc 	if (arch_fb_init(minor, infop) == OK) {
75433d6423SLionel Sambuc 		open_counter[minor]++;
76433d6423SLionel Sambuc 		if (!initialized) {
77433d6423SLionel Sambuc 			if (has_restarted) {
78433d6423SLionel Sambuc 				read_frclock_64(&has_restarted_t1);
79433d6423SLionel Sambuc 				paint_restartlogo(minor);
80433d6423SLionel Sambuc 			} else {
81433d6423SLionel Sambuc 				paint_bootlogo(minor);
82433d6423SLionel Sambuc 			}
83433d6423SLionel Sambuc 			initialized = 1;
84433d6423SLionel Sambuc 		}
85433d6423SLionel Sambuc 		return OK;
86433d6423SLionel Sambuc 	}
87433d6423SLionel Sambuc 	return ENXIO;
88433d6423SLionel Sambuc }
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc static int
fb_close(devminor_t minor)91433d6423SLionel Sambuc fb_close(devminor_t minor)
92433d6423SLionel Sambuc {
93433d6423SLionel Sambuc 	if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
94433d6423SLionel Sambuc 	assert(open_counter[minor] > 0);
95433d6423SLionel Sambuc 	open_counter[minor]--;
96433d6423SLionel Sambuc 	return OK;
97433d6423SLionel Sambuc }
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc static ssize_t
fb_read(devminor_t minor,u64_t pos,endpoint_t ep,cp_grant_id_t gid,size_t size,int UNUSED (flags),cdev_id_t UNUSED (id))100433d6423SLionel Sambuc fb_read(devminor_t minor, u64_t pos, endpoint_t ep, cp_grant_id_t gid,
101433d6423SLionel Sambuc 	size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
102433d6423SLionel Sambuc {
103433d6423SLionel Sambuc 	struct device dev;
104433d6423SLionel Sambuc 	int r;
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc 	if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
107433d6423SLionel Sambuc 	assert(open_counter[minor] > 0);
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc 	arch_get_device(minor, &dev);
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc 	if (size == 0 || pos >= dev.dv_size) return 0;
112433d6423SLionel Sambuc 	if (pos + size > dev.dv_size)
113433d6423SLionel Sambuc 		size = (size_t)(dev.dv_size - pos);
114433d6423SLionel Sambuc 
115433d6423SLionel Sambuc 	r = sys_safecopyto(ep, gid, 0, (vir_bytes)(dev.dv_base + (size_t)pos),
116433d6423SLionel Sambuc 	    size);
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc 	return (r != OK) ? r : size;
119433d6423SLionel Sambuc }
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc static int
fb_ioctl(devminor_t minor,unsigned long request,endpoint_t ep,cp_grant_id_t gid,int UNUSED (flags),endpoint_t UNUSED (user_ep),cdev_id_t UNUSED (id))122433d6423SLionel Sambuc fb_ioctl(devminor_t minor, unsigned long request, endpoint_t ep,
123433d6423SLionel Sambuc 	cp_grant_id_t gid, int UNUSED(flags), endpoint_t UNUSED(user_ep),
124433d6423SLionel Sambuc 	cdev_id_t UNUSED(id))
125433d6423SLionel Sambuc {
126433d6423SLionel Sambuc /* Process I/O control requests */
127433d6423SLionel Sambuc 	int r;
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc 	if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc 	switch(request) {
132433d6423SLionel Sambuc 	case FBIOGET_VSCREENINFO:
133433d6423SLionel Sambuc 		r = do_get_varscreeninfo(minor, ep, gid);
134433d6423SLionel Sambuc 		return r;
135433d6423SLionel Sambuc 	case FBIOPUT_VSCREENINFO:
136433d6423SLionel Sambuc 		r = do_put_varscreeninfo(minor, ep, gid);
137433d6423SLionel Sambuc 		return r;
138433d6423SLionel Sambuc 	case FBIOGET_FSCREENINFO:
139433d6423SLionel Sambuc 		r = do_get_fixscreeninfo(minor, ep, gid);
140433d6423SLionel Sambuc 		return r;
141433d6423SLionel Sambuc 	case FBIOPAN_DISPLAY:
142433d6423SLionel Sambuc 		r = do_pan_display(minor, ep, gid);
143433d6423SLionel Sambuc 		return r;
144433d6423SLionel Sambuc 	}
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 	return ENOTTY;
147433d6423SLionel Sambuc }
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc static int
do_get_varscreeninfo(int minor,endpoint_t ep,cp_grant_id_t gid)150433d6423SLionel Sambuc do_get_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid)
151433d6423SLionel Sambuc {
152433d6423SLionel Sambuc 	int r;
153433d6423SLionel Sambuc 	struct fb_var_screeninfo fbvs;
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc 	if ((r = arch_get_varscreeninfo(minor, &fbvs)) == OK) {
156433d6423SLionel Sambuc 		r = sys_safecopyto(ep, gid, 0, (vir_bytes) &fbvs, sizeof(fbvs));
157433d6423SLionel Sambuc 	}
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc 	return r;
160433d6423SLionel Sambuc }
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc static int
do_put_varscreeninfo(int minor,endpoint_t ep,cp_grant_id_t gid)163433d6423SLionel Sambuc do_put_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid)
164433d6423SLionel Sambuc {
165433d6423SLionel Sambuc 	int r;
166433d6423SLionel Sambuc 	struct fb_var_screeninfo fbvs_copy;
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc 	if (has_restarted && keep_displaying_restarted()) {
169433d6423SLionel Sambuc 		return EAGAIN;
170433d6423SLionel Sambuc 	}
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc 	if ((r = sys_safecopyfrom(ep, gid, 0, (vir_bytes) &fbvs_copy,
173433d6423SLionel Sambuc 	    sizeof(fbvs_copy))) != OK) {
174433d6423SLionel Sambuc 		return r;
175433d6423SLionel Sambuc 	}
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc 	return arch_put_varscreeninfo(minor, &fbvs_copy);
178433d6423SLionel Sambuc }
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc static int
do_pan_display(int minor,endpoint_t ep,cp_grant_id_t gid)181433d6423SLionel Sambuc do_pan_display(int minor, endpoint_t ep, cp_grant_id_t gid)
182433d6423SLionel Sambuc {
183433d6423SLionel Sambuc 	int r;
184433d6423SLionel Sambuc         struct fb_var_screeninfo fbvs_copy;
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc 	if (has_restarted && keep_displaying_restarted()) {
187433d6423SLionel Sambuc 		return EAGAIN;
188433d6423SLionel Sambuc 	}
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc         if ((r = sys_safecopyfrom(ep, gid, 0, (vir_bytes) &fbvs_copy,
191433d6423SLionel Sambuc             sizeof(fbvs_copy))) != OK) {
192433d6423SLionel Sambuc                 return r;
193433d6423SLionel Sambuc         }
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc         return arch_pan_display(minor, &fbvs_copy);
196433d6423SLionel Sambuc }
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc static int
do_get_fixscreeninfo(int minor,endpoint_t ep,cp_grant_id_t gid)199433d6423SLionel Sambuc do_get_fixscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid)
200433d6423SLionel Sambuc {
201433d6423SLionel Sambuc         int r;
202433d6423SLionel Sambuc         struct fb_fix_screeninfo fbfs;
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc         if ((r = arch_get_fixscreeninfo(minor, &fbfs)) == OK) {
205433d6423SLionel Sambuc                 r = sys_safecopyto(ep, gid, 0, (vir_bytes) &fbfs, sizeof(fbfs));
206433d6423SLionel Sambuc         }
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc         return r;
209433d6423SLionel Sambuc }
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc static ssize_t
fb_write(devminor_t minor,u64_t pos,endpoint_t ep,cp_grant_id_t gid,size_t size,int UNUSED (flags),cdev_id_t UNUSED (id))212433d6423SLionel Sambuc fb_write(devminor_t minor, u64_t pos, endpoint_t ep, cp_grant_id_t gid,
213433d6423SLionel Sambuc 	size_t size, int UNUSED(flags), cdev_id_t UNUSED(id))
214433d6423SLionel Sambuc {
215433d6423SLionel Sambuc 	struct device dev;
216433d6423SLionel Sambuc 	int r;
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc 	if (minor < 0 || minor >= FB_DEV_NR) return ENXIO;
219433d6423SLionel Sambuc 	assert(open_counter[minor] > 0);
220433d6423SLionel Sambuc 
221433d6423SLionel Sambuc 	if (has_restarted && keep_displaying_restarted())
222433d6423SLionel Sambuc 		return EAGAIN;
223433d6423SLionel Sambuc 
224433d6423SLionel Sambuc 	arch_get_device(minor, &dev);
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc 	if (size == 0 || pos >= dev.dv_size) return 0;
227433d6423SLionel Sambuc 	if (pos + size > dev.dv_size)
228433d6423SLionel Sambuc 		size = (size_t)(dev.dv_size - pos);
229433d6423SLionel Sambuc 
230433d6423SLionel Sambuc 	r = sys_safecopyfrom(ep, gid, 0,
231433d6423SLionel Sambuc 	    (vir_bytes)(dev.dv_base + (size_t)pos), size);
232433d6423SLionel Sambuc 
233433d6423SLionel Sambuc 	return (r != OK) ? r : size;
234433d6423SLionel Sambuc }
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc static int
sef_cb_lu_state_save(int UNUSED (result),int UNUSED (flags))237*e1f889d2SCristiano Giuffrida sef_cb_lu_state_save(int UNUSED(result), int UNUSED(flags))
238*e1f889d2SCristiano Giuffrida {
239433d6423SLionel Sambuc /* Save the state. */
240433d6423SLionel Sambuc 	ds_publish_u32("open_counter", open_counter[0], DSF_OVERWRITE);
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc 	return OK;
243433d6423SLionel Sambuc }
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc static int
lu_state_restore()246433d6423SLionel Sambuc lu_state_restore() {
247433d6423SLionel Sambuc /* Restore the state. */
248433d6423SLionel Sambuc 	u32_t value;
249433d6423SLionel Sambuc 
250433d6423SLionel Sambuc 	ds_retrieve_u32("open_counter", &value);
251433d6423SLionel Sambuc 	ds_delete_u32("open_counter");
252433d6423SLionel Sambuc 	open_counter[0] = (int) value;
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc 	return OK;
255433d6423SLionel Sambuc }
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc static int
sef_cb_init(int type,sef_init_info_t * UNUSED (info))258433d6423SLionel Sambuc sef_cb_init(int type, sef_init_info_t *UNUSED(info))
259433d6423SLionel Sambuc {
260433d6423SLionel Sambuc /* Initialize the fb driver. */
261433d6423SLionel Sambuc 	int do_announce_driver = TRUE;
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 	open_counter[0] = 0;
264433d6423SLionel Sambuc 	switch(type) {
265433d6423SLionel Sambuc 	case SEF_INIT_FRESH:
266433d6423SLionel Sambuc 	    printf("framebuffer fresh: pid %d\n", getpid());
267433d6423SLionel Sambuc 	    break;
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 	case SEF_INIT_LU:
270433d6423SLionel Sambuc 	    /* Restore the state. */
271433d6423SLionel Sambuc 	    lu_state_restore();
272433d6423SLionel Sambuc 	    do_announce_driver = FALSE;
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc 	    printf("framebuffer: I'm a new version!\n");
275433d6423SLionel Sambuc 	    break;
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc 	case SEF_INIT_RESTART:
278433d6423SLionel Sambuc 	    printf("framebuffer restarted: pid %d\n", getpid());
279433d6423SLionel Sambuc 	    has_restarted = 1;
280433d6423SLionel Sambuc 	    break;
281433d6423SLionel Sambuc 	}
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc 	/* Announce we are up when necessary. */
284433d6423SLionel Sambuc 	if (do_announce_driver) {
285433d6423SLionel Sambuc 		chardriver_announce();
286433d6423SLionel Sambuc 	}
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc 	/* Initialization completed successfully. */
289433d6423SLionel Sambuc 	return OK;
290433d6423SLionel Sambuc }
291433d6423SLionel Sambuc 
292*e1f889d2SCristiano Giuffrida static void
sef_local_startup()293*e1f889d2SCristiano Giuffrida sef_local_startup()
294*e1f889d2SCristiano Giuffrida {
295*e1f889d2SCristiano Giuffrida 	/* Register init callbacks. Use the same function for all event types */
296*e1f889d2SCristiano Giuffrida 	sef_setcb_init_fresh(sef_cb_init);
297*e1f889d2SCristiano Giuffrida 	sef_setcb_init_lu(sef_cb_init);
298*e1f889d2SCristiano Giuffrida 	sef_setcb_init_restart(sef_cb_init);
299*e1f889d2SCristiano Giuffrida 
300*e1f889d2SCristiano Giuffrida 	/* Register live update callbacks  */
301*e1f889d2SCristiano Giuffrida 	sef_setcb_lu_state_save(sef_cb_lu_state_save);
302*e1f889d2SCristiano Giuffrida 
303*e1f889d2SCristiano Giuffrida 	/* Let SEF perform startup. */
304*e1f889d2SCristiano Giuffrida 	sef_startup();
305*e1f889d2SCristiano Giuffrida }
306*e1f889d2SCristiano Giuffrida 
307433d6423SLionel Sambuc int
main(int argc,char * argv[])308433d6423SLionel Sambuc main(int argc, char *argv[])
309433d6423SLionel Sambuc {
310433d6423SLionel Sambuc 	env_setargs(argc, argv);
311433d6423SLionel Sambuc 	fb_edid_args_parse();
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc 	sef_local_startup();
314433d6423SLionel Sambuc 	chardriver_task(&fb_tab);
315433d6423SLionel Sambuc 	return OK;
316433d6423SLionel Sambuc }
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc static int
keep_displaying_restarted()319433d6423SLionel Sambuc keep_displaying_restarted()
320433d6423SLionel Sambuc {
321433d6423SLionel Sambuc 	u64_t delta;
322433d6423SLionel Sambuc 	u32_t micro_delta;
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc 	read_frclock_64(&has_restarted_t2);
325433d6423SLionel Sambuc 	delta = delta_frclock_64(has_restarted_t1, has_restarted_t2);
326433d6423SLionel Sambuc 	micro_delta = frclock_64_to_micros(delta);
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc #define DISPLAY_1SEC 1000000	/* 1 second in microseconds */
329433d6423SLionel Sambuc 	if (micro_delta < DISPLAY_1SEC) {
330433d6423SLionel Sambuc 		return 1;
331433d6423SLionel Sambuc 	}
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc 	has_restarted = 0;
334433d6423SLionel Sambuc 	return 0;
335433d6423SLionel Sambuc }
336433d6423SLionel Sambuc 
337433d6423SLionel Sambuc static void
paint_bootlogo(int minor)338433d6423SLionel Sambuc paint_bootlogo(int minor)
339433d6423SLionel Sambuc {
340433d6423SLionel Sambuc 	paint_centered(minor, bootlogo_data, bootlogo_width, bootlogo_height);
341433d6423SLionel Sambuc }
342433d6423SLionel Sambuc 
343433d6423SLionel Sambuc static void
paint_restartlogo(int minor)344433d6423SLionel Sambuc paint_restartlogo(int minor)
345433d6423SLionel Sambuc {
346433d6423SLionel Sambuc 	paint_centered(minor, restartlogo_data, restartlogo_width,
347433d6423SLionel Sambuc 			restartlogo_height);
348433d6423SLionel Sambuc }
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc static void
paint_centered(int minor,char * data,int width,int height)351433d6423SLionel Sambuc paint_centered(int minor, char *data, int width, int height)
352433d6423SLionel Sambuc {
353433d6423SLionel Sambuc 	u8_t pixel[3];
354433d6423SLionel Sambuc 	u32_t i, min_x, min_y, max_x, max_y, x_painted = 0, rows = 0;
355433d6423SLionel Sambuc 	int r, bytespp;
356433d6423SLionel Sambuc 	struct device dev;
357433d6423SLionel Sambuc 	struct fb_var_screeninfo fbvs;
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 	/* Put display in a known state to simplify positioning code below */
360433d6423SLionel Sambuc 	if ((r = arch_get_varscreeninfo(minor, &fbvs)) != OK) {
361433d6423SLionel Sambuc 		printf("fb: unable to get screen info: %d\n", r);
362433d6423SLionel Sambuc 	}
363433d6423SLionel Sambuc 	fbvs.yoffset = 0;
364433d6423SLionel Sambuc 	if ((r = arch_pan_display(minor, &fbvs)) != OK) {
365433d6423SLionel Sambuc 		printf("fb: unable to pan display: %d\n", r);
366433d6423SLionel Sambuc 	}
367433d6423SLionel Sambuc 
368433d6423SLionel Sambuc 	arch_get_device(minor, &dev);
369433d6423SLionel Sambuc 
370433d6423SLionel Sambuc 	/* Paint on a white canvas */
371433d6423SLionel Sambuc 	bytespp = fbvs.bits_per_pixel / 8;
372433d6423SLionel Sambuc 	for (i = 0; i < fbvs.xres * fbvs.yres * bytespp; i+= bytespp)
373433d6423SLionel Sambuc 		*((u32_t *)((u32_t) dev.dv_base + i)) = 0x00FFFFFF;
374433d6423SLionel Sambuc 
375433d6423SLionel Sambuc 	/* First seek to start */
376433d6423SLionel Sambuc 	min_x = fbvs.xres / 2 - width / 2;
377433d6423SLionel Sambuc 	max_x = fbvs.xres / 2 + width / 2;
378433d6423SLionel Sambuc 	min_y = fbvs.yres / 2 - height / 2;
379433d6423SLionel Sambuc 	max_y = fbvs.yres / 2 + height / 2;
380433d6423SLionel Sambuc 	i = min_x * fbvs.xres + min_y;
381433d6423SLionel Sambuc 
382433d6423SLionel Sambuc 	/* Add the image data */
383433d6423SLionel Sambuc 	for (i = ((min_y * fbvs.xres) + min_x) * bytespp; rows < height;) {
384433d6423SLionel Sambuc 		GET_PIXEL(data, pixel);
385433d6423SLionel Sambuc 
386433d6423SLionel Sambuc 		((unsigned char *)((u32_t) dev.dv_base + i))[0] = pixel[2];
387433d6423SLionel Sambuc 		((unsigned char *)((u32_t) dev.dv_base + i))[1] = pixel[1];
388433d6423SLionel Sambuc                 ((unsigned char *)((u32_t) dev.dv_base + i))[2] = pixel[0];
389433d6423SLionel Sambuc 		((unsigned char *)((u32_t) dev.dv_base + i))[3] = 0;
390433d6423SLionel Sambuc 
391433d6423SLionel Sambuc 		x_painted++;/* Keep tab of how many row pixels we've painted */
392433d6423SLionel Sambuc 		if (x_painted == width) {
393433d6423SLionel Sambuc 			/* We've reached the end of the row, carriage return
394433d6423SLionel Sambuc 			 * and go to next line.
395433d6423SLionel Sambuc 			 */
396433d6423SLionel Sambuc 			x_painted = 0;
397433d6423SLionel Sambuc 			rows++;
398433d6423SLionel Sambuc 			i = (((min_y + rows) * fbvs.xres) + min_x) * 4;
399433d6423SLionel Sambuc 		} else {
400433d6423SLionel Sambuc 			i += 4;
401433d6423SLionel Sambuc 		}
402433d6423SLionel Sambuc 	}
403433d6423SLionel Sambuc }
404433d6423SLionel Sambuc 
405