2 #include <minix/chardriver.h>
3 #include <minix/drivers.h>
5 #include <minix/sysutil.h>
6 #include <minix/type.h>
8 #include <sys/ioc_fb.h>
10 #include <sys/ioctl.h>
15 #include <dev/videomode/videomode.h>
16 #include <dev/videomode/edidvar.h>
17 #include <dev/videomode/edidreg.h>
24 * Function prototypes for the fb driver.
26 static int fb_open(devminor_t minor
, int access
, endpoint_t user_endpt
);
27 static int fb_close(devminor_t minor
);
28 static ssize_t
fb_read(devminor_t minor
, u64_t pos
, endpoint_t ep
,
29 cp_grant_id_t gid
, size_t size
, int flags
, cdev_id_t id
);
30 static ssize_t
fb_write(devminor_t minor
, u64_t pos
, endpoint_t ep
,
31 cp_grant_id_t gid
, size_t size
, int flags
, cdev_id_t id
);
32 static int fb_ioctl(devminor_t minor
, unsigned long request
, endpoint_t ep
,
33 cp_grant_id_t gid
, int flags
, endpoint_t user_ep
, cdev_id_t id
);
34 static void paint_bootlogo(int minor
);
35 static void paint_restartlogo(int minor
);
36 static void paint_centered(int minor
, char *data
, int width
, int height
);
37 static int do_get_varscreeninfo(int minor
, endpoint_t ep
, cp_grant_id_t gid
);
38 static int do_put_varscreeninfo(int minor
, endpoint_t ep
, cp_grant_id_t gid
);
39 static int do_get_fixscreeninfo(int minor
, endpoint_t ep
, cp_grant_id_t gid
);
40 static int do_pan_display(int minor
, endpoint_t ep
, cp_grant_id_t gid
);
41 static int keep_displaying_restarted(void);
43 /* SEF functions and variables. */
44 static void sef_local_startup(void);
45 static int sef_cb_init(int type
, sef_init_info_t
*info
);
46 static int sef_cb_lu_state_save(int);
47 static int lu_state_restore(void);
49 /* Entry points to the fb driver. */
50 static struct chardriver fb_tab
=
53 .cdr_close
= fb_close
,
55 .cdr_write
= fb_write
,
59 /** Represents the /dev/fb device. */
60 static int has_restarted
= 0;
61 static u64_t has_restarted_t1
, has_restarted_t2
;
63 static int open_counter
[FB_DEV_NR
]; /* Open count */
66 fb_open(devminor_t minor
, int UNUSED(access
), endpoint_t
UNUSED(user_endpt
))
69 static int initialized
= 0;
70 static struct edid_info info
;
71 static struct edid_info
*infop
= NULL
;
73 if (minor
< 0 || minor
>= FB_DEV_NR
) return ENXIO
;
76 r
= fb_edid_read(minor
, &info
);
77 infop
= (r
== 0) ? &info
: NULL
;
80 if (arch_fb_init(minor
, infop
) == OK
) {
81 open_counter
[minor
]++;
84 read_frclock_64(&has_restarted_t1
);
85 paint_restartlogo(minor
);
87 paint_bootlogo(minor
);
97 fb_close(devminor_t minor
)
99 if (minor
< 0 || minor
>= FB_DEV_NR
) return ENXIO
;
100 assert(open_counter
[minor
] > 0);
101 open_counter
[minor
]--;
106 fb_read(devminor_t minor
, u64_t pos
, endpoint_t ep
, cp_grant_id_t gid
,
107 size_t size
, int UNUSED(flags
), cdev_id_t
UNUSED(id
))
112 if (minor
< 0 || minor
>= FB_DEV_NR
) return ENXIO
;
113 assert(open_counter
[minor
] > 0);
115 arch_get_device(minor
, &dev
);
117 if (size
== 0 || pos
>= dev
.dv_size
) return 0;
118 if (pos
+ size
> dev
.dv_size
)
119 size
= (size_t)(dev
.dv_size
- pos
);
121 r
= sys_safecopyto(ep
, gid
, 0, (vir_bytes
)(dev
.dv_base
+ (size_t)pos
),
124 return (r
!= OK
) ? r
: size
;
128 fb_ioctl(devminor_t minor
, unsigned long request
, endpoint_t ep
,
129 cp_grant_id_t gid
, int UNUSED(flags
), endpoint_t
UNUSED(user_ep
),
130 cdev_id_t
UNUSED(id
))
132 /* Process I/O control requests */
135 if (minor
< 0 || minor
>= FB_DEV_NR
) return ENXIO
;
138 case FBIOGET_VSCREENINFO
:
139 r
= do_get_varscreeninfo(minor
, ep
, gid
);
141 case FBIOPUT_VSCREENINFO
:
142 r
= do_put_varscreeninfo(minor
, ep
, gid
);
144 case FBIOGET_FSCREENINFO
:
145 r
= do_get_fixscreeninfo(minor
, ep
, gid
);
147 case FBIOPAN_DISPLAY
:
148 r
= do_pan_display(minor
, ep
, gid
);
156 do_get_varscreeninfo(int minor
, endpoint_t ep
, cp_grant_id_t gid
)
159 struct fb_var_screeninfo fbvs
;
161 if ((r
= arch_get_varscreeninfo(minor
, &fbvs
)) == OK
) {
162 r
= sys_safecopyto(ep
, gid
, 0, (vir_bytes
) &fbvs
, sizeof(fbvs
));
169 do_put_varscreeninfo(int minor
, endpoint_t ep
, cp_grant_id_t gid
)
172 struct fb_var_screeninfo fbvs_copy
;
174 if (has_restarted
&& keep_displaying_restarted()) {
178 if ((r
= sys_safecopyfrom(ep
, gid
, 0, (vir_bytes
) &fbvs_copy
,
179 sizeof(fbvs_copy
))) != OK
) {
183 return arch_put_varscreeninfo(minor
, &fbvs_copy
);
187 do_pan_display(int minor
, endpoint_t ep
, cp_grant_id_t gid
)
190 struct fb_var_screeninfo fbvs_copy
;
192 if (has_restarted
&& keep_displaying_restarted()) {
196 if ((r
= sys_safecopyfrom(ep
, gid
, 0, (vir_bytes
) &fbvs_copy
,
197 sizeof(fbvs_copy
))) != OK
) {
201 return arch_pan_display(minor
, &fbvs_copy
);
205 do_get_fixscreeninfo(int minor
, endpoint_t ep
, cp_grant_id_t gid
)
208 struct fb_fix_screeninfo fbfs
;
210 if ((r
= arch_get_fixscreeninfo(minor
, &fbfs
)) == OK
) {
211 r
= sys_safecopyto(ep
, gid
, 0, (vir_bytes
) &fbfs
, sizeof(fbfs
));
218 fb_write(devminor_t minor
, u64_t pos
, endpoint_t ep
, cp_grant_id_t gid
,
219 size_t size
, int UNUSED(flags
), cdev_id_t
UNUSED(id
))
224 if (minor
< 0 || minor
>= FB_DEV_NR
) return ENXIO
;
225 assert(open_counter
[minor
] > 0);
227 if (has_restarted
&& keep_displaying_restarted())
230 arch_get_device(minor
, &dev
);
232 if (size
== 0 || pos
>= dev
.dv_size
) return 0;
233 if (pos
+ size
> dev
.dv_size
)
234 size
= (size_t)(dev
.dv_size
- pos
);
236 r
= sys_safecopyfrom(ep
, gid
, 0,
237 (vir_bytes
)(dev
.dv_base
+ (size_t)pos
), size
);
239 return (r
!= OK
) ? r
: size
;
243 sef_cb_lu_state_save(int UNUSED(state
)) {
244 /* Save the state. */
245 ds_publish_u32("open_counter", open_counter
[0], DSF_OVERWRITE
);
252 /* Restore the state. */
255 ds_retrieve_u32("open_counter", &value
);
256 ds_delete_u32("open_counter");
257 open_counter
[0] = (int) value
;
265 /* Register init callbacks. Use the same function for all event types */
266 sef_setcb_init_fresh(sef_cb_init
);
267 sef_setcb_init_lu(sef_cb_init
);
268 sef_setcb_init_restart(sef_cb_init
);
270 /* Register live update callbacks */
271 /* - Agree to update immediately when LU is requested in a valid state*/
272 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready
);
273 /* - Support live update starting from any standard state */
274 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard
);
275 /* - Register a custom routine to save the state. */
276 sef_setcb_lu_state_save(sef_cb_lu_state_save
);
278 /* Let SEF perform startup. */
283 sef_cb_init(int type
, sef_init_info_t
*UNUSED(info
))
285 /* Initialize the fb driver. */
286 int do_announce_driver
= TRUE
;
291 printf("framebuffer fresh: pid %d\n", getpid());
295 /* Restore the state. */
297 do_announce_driver
= FALSE
;
299 printf("framebuffer: I'm a new version!\n");
302 case SEF_INIT_RESTART
:
303 printf("framebuffer restarted: pid %d\n", getpid());
308 /* Announce we are up when necessary. */
309 if (do_announce_driver
) {
310 chardriver_announce();
313 /* Initialization completed successfully. */
318 main(int argc
, char *argv
[])
320 env_setargs(argc
, argv
);
321 fb_edid_args_parse();
324 chardriver_task(&fb_tab
);
329 keep_displaying_restarted()
334 read_frclock_64(&has_restarted_t2
);
335 delta
= delta_frclock_64(has_restarted_t1
, has_restarted_t2
);
336 micro_delta
= frclock_64_to_micros(delta
);
338 #define DISPLAY_1SEC 1000000 /* 1 second in microseconds */
339 if (micro_delta
< DISPLAY_1SEC
) {
348 paint_bootlogo(int minor
)
350 paint_centered(minor
, bootlogo_data
, bootlogo_width
, bootlogo_height
);
354 paint_restartlogo(int minor
)
356 paint_centered(minor
, restartlogo_data
, restartlogo_width
,
361 paint_centered(int minor
, char *data
, int width
, int height
)
364 u32_t i
, min_x
, min_y
, max_x
, max_y
, x_painted
= 0, rows
= 0;
367 struct fb_var_screeninfo fbvs
;
369 /* Put display in a known state to simplify positioning code below */
370 if ((r
= arch_get_varscreeninfo(minor
, &fbvs
)) != OK
) {
371 printf("fb: unable to get screen info: %d\n", r
);
374 if ((r
= arch_pan_display(minor
, &fbvs
)) != OK
) {
375 printf("fb: unable to pan display: %d\n", r
);
378 arch_get_device(minor
, &dev
);
380 /* Paint on a white canvas */
381 bytespp
= fbvs
.bits_per_pixel
/ 8;
382 for (i
= 0; i
< fbvs
.xres
* fbvs
.yres
* bytespp
; i
+= bytespp
)
383 *((u32_t
*)((u32_t
) dev
.dv_base
+ i
)) = 0x00FFFFFF;
385 /* First seek to start */
386 min_x
= fbvs
.xres
/ 2 - width
/ 2;
387 max_x
= fbvs
.xres
/ 2 + width
/ 2;
388 min_y
= fbvs
.yres
/ 2 - height
/ 2;
389 max_y
= fbvs
.yres
/ 2 + height
/ 2;
390 i
= min_x
* fbvs
.xres
+ min_y
;
392 /* Add the image data */
393 for (i
= ((min_y
* fbvs
.xres
) + min_x
) * bytespp
; rows
< height
;) {
394 GET_PIXEL(data
, pixel
);
396 ((unsigned char *)((u32_t
) dev
.dv_base
+ i
))[0] = pixel
[2];
397 ((unsigned char *)((u32_t
) dev
.dv_base
+ i
))[1] = pixel
[1];
398 ((unsigned char *)((u32_t
) dev
.dv_base
+ i
))[2] = pixel
[0];
399 ((unsigned char *)((u32_t
) dev
.dv_base
+ i
))[3] = 0;
401 x_painted
++;/* Keep tab of how many row pixels we've painted */
402 if (x_painted
== width
) {
403 /* We've reached the end of the row, carriage return
404 * and go to next line.
408 i
= (((min_y
+ rows
) * fbvs
.xres
) + min_x
) * 4;