[PATCH] fbdev: initialization of varinfo reorder and storage

mchalain [marc.chalain@gmail.com] marc.chalain at gmail.com
Tue Jun 25 07:21:40 PDT 2013


From: mchalain <marc.chalain at gmail.com>

Currently the frame buffer initalization is uncomplete and the reenable
uses different values as the startup. To set the frame buffer with values
and to be sure of the configuration's result, this patch reorder the
initialization sequence.
The new order is:
 - read the weston.ini to set the resolution
 - open the device
 - get the device info from device
 - try to set the weston.ini resolution
 - get the resulting device info
 - store the device info
 - map the device memory
 - close the device
runing
 - VT_LEAVE
device access disabling
 - VT_ENTER
 - reenable the framebuffer
 - open the device
 - set the device info from storage
 - map the device memory
 - close the device

the fbdev-backend read some configurations from
weston.ini in the [output] section.
name is the name of the device (default "fb0")
mode to read the resolution
transform to change the screen rotation
---
 src/compositor-fbdev.c |  254 ++++++++++++++++++++++++++----------------------
 1 file changed, 138 insertions(+), 116 deletions(-)

diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 9c3d17e..349833a 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -56,11 +56,7 @@ struct fbdev_compositor {
 };
 
 struct fbdev_screeninfo {
-	unsigned int x_resolution; /* pixels, visible area */
-	unsigned int y_resolution; /* pixels, visible area */
-	unsigned int width_mm; /* visible screen width in mm */
-	unsigned int height_mm; /* visible screen height in mm */
-	unsigned int bits_per_pixel;
+	struct fb_var_screeninfo varinfo;
 
 	size_t buffer_length; /* length of frame buffer memory in bytes */
 	size_t line_length; /* length of a line in bytes */
@@ -203,6 +199,61 @@ finish_frame_handler(void *data)
 	return 1;
 }
 
+static uint32_t
+parse_transform(const char *transform, const char *output_name)
+{
+	static const struct { const char *name; uint32_t token; } names[] = {
+		{ "normal",	WL_OUTPUT_TRANSFORM_NORMAL },
+		{ "90",		WL_OUTPUT_TRANSFORM_90 },
+		{ "180",	WL_OUTPUT_TRANSFORM_180 },
+		{ "270",	WL_OUTPUT_TRANSFORM_270 },
+		{ "flipped",	WL_OUTPUT_TRANSFORM_FLIPPED },
+		{ "flipped-90",	WL_OUTPUT_TRANSFORM_FLIPPED_90 },
+		{ "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
+		{ "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
+	};
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_LENGTH(names); i++)
+		if (strcmp(names[i].name, transform) == 0)
+			return names[i].token;
+
+	weston_log("Invalid transform \"%s\" for output %s\n",
+		   transform, output_name);
+
+	return WL_OUTPUT_TRANSFORM_NORMAL;
+}
+
+static int
+fbdev_read_config(struct fbdev_compositor *ec,
+			struct fbdev_output *output)
+{
+	struct weston_config_section *section;
+	char *s;
+
+	weston_log("output name %s\n", output->base.name);
+	memset(&output->fb_info.varinfo, 0, sizeof(output->fb_info.varinfo));
+	output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL;
+	section = weston_config_get_section(ec->base.config, "output", "name",
+					    output->base.name);
+	if (section) {
+		weston_config_section_get_string(section, "mode", &s, "preferred");
+		if (strcmp(s, "preferred") == 0) {
+			output->fb_info.varinfo.xres = 0;
+			output->fb_info.varinfo.yres = 0;
+		} else if (sscanf(s, "%dx%d", &output->fb_info.varinfo.xres,
+				&output->fb_info.varinfo.yres) != 2) {
+			weston_log("Invalid mode \"%s\" for output %s\n",
+				   s, output->base.name);
+		}
+		free(s);
+
+		weston_config_section_get_string(section, "transform", &s, "normal");
+		output->base.transform = parse_transform(s, output->base.name);
+		free(s);
+	}
+	return 0;
+}
 static pixman_format_code_t
 calculate_pixman_format(struct fb_var_screeninfo *vinfo,
                         struct fb_fix_screeninfo *finfo)
@@ -219,32 +270,10 @@ calculate_pixman_format(struct fb_var_screeninfo *vinfo,
 	 * the preferred format in the hardware. */
 	int type;
 
-	weston_log("Calculating pixman format from:\n"
-	           STAMP_SPACE " - type: %i (aux: %i)\n"
-	           STAMP_SPACE " - visual: %i\n"
-	           STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
-	           STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
-	           STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
-	           STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
-	           STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
-	           finfo->type, finfo->type_aux, finfo->visual,
-	           vinfo->bits_per_pixel, vinfo->grayscale,
-	           vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
-	           vinfo->green.offset, vinfo->green.length,
-	           vinfo->green.msb_right,
-	           vinfo->blue.offset, vinfo->blue.length,
-	           vinfo->blue.msb_right,
-	           vinfo->transp.offset, vinfo->transp.length,
-	           vinfo->transp.msb_right);
-
 	/* We only handle packed formats at the moment. */
 	if (finfo->type != FB_TYPE_PACKED_PIXELS)
 		return 0;
 
-	/* We only handle true-colour frame buffers at the moment. */
-	if (finfo->visual != FB_VISUAL_TRUECOLOR || vinfo->grayscale != 0)
-		return 0;
-
 	/* We only support formats with MSBs on the left. */
 	if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
 	    vinfo->blue.msb_right != 0)
@@ -299,7 +328,7 @@ calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
 }
 
 static int
-fbdev_query_screen_info(struct fbdev_output *output, int fd,
+fbdev_frame_buffer_set(struct fbdev_output *output, int fd,
                         struct fbdev_screeninfo *info)
 {
 	struct fb_var_screeninfo varinfo;
@@ -312,16 +341,56 @@ fbdev_query_screen_info(struct fbdev_output *output, int fd,
 	}
 
 	/* Store the pertinent data. */
-	info->x_resolution = varinfo.xres;
-	info->y_resolution = varinfo.yres;
-	info->width_mm = varinfo.width;
-	info->height_mm = varinfo.height;
-	info->bits_per_pixel = varinfo.bits_per_pixel;
+	if (info->varinfo.xres)
+		varinfo.xres = info->varinfo.xres;
+	if (info->varinfo.yres)
+		varinfo.yres = info->varinfo.yres;
+	varinfo.yoffset	= 0;
+	varinfo.xoffset	= 0;
+	/* if we need to set more info to the frame buffer we can do it here */
+
+	/* try the new framebuffer configuration */
+	/* if the PUT is in error , the next step get the good values */
+	ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo);
+	/* retrieve the good values of varinfo */
+	if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
+		return -1;
+	}
+	/* store the framebuffer varinfo used by the device */
+	memcpy(&info->varinfo, &varinfo, sizeof(varinfo));
 
+	/* continue to set the informations */
 	info->buffer_length = fixinfo.smem_len;
 	info->line_length = fixinfo.line_length;
 	strncpy(info->id, fixinfo.id, sizeof(info->id) / sizeof(*info->id));
 
+	weston_log("Calculating pixman format from:\n"
+				STAMP_SPACE " - type: %i (aux: %i)\n"
+				STAMP_SPACE " - visual: %i\n"
+				STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
+				STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
+				STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
+				STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
+				STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
+				fixinfo.type, fixinfo.type_aux, fixinfo.visual,
+				varinfo.bits_per_pixel, varinfo.grayscale,
+				varinfo.red.offset, varinfo.red.length,
+				 varinfo.red.msb_right,
+				varinfo.green.offset, varinfo.green.length,
+				 varinfo.green.msb_right,
+				varinfo.blue.offset, varinfo.blue.length,
+				 varinfo.blue.msb_right,
+				varinfo.transp.offset, varinfo.transp.length,
+				 varinfo.transp.msb_right);
+
+	/* We only handle true-colour and direct-color frame buffers at the moment. */
+	if (!(fixinfo.visual == FB_VISUAL_TRUECOLOR
+				|| fixinfo.visual == FB_VISUAL_DIRECTCOLOR)
+			|| varinfo.grayscale != 0) {
+		weston_log("unsupported frame buffer\n");
+		return -1;
+	}
+
 	info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
 	info->refresh_rate = calculate_refresh_rate(&varinfo);
 
@@ -337,37 +406,8 @@ static int
 fbdev_set_screen_info(struct fbdev_output *output, int fd,
                       struct fbdev_screeninfo *info)
 {
-	struct fb_var_screeninfo varinfo;
-
-	/* Grab the current screen information. */
-	if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
-		return -1;
-	}
-
-	/* Update the information. */
-	varinfo.xres = info->x_resolution;
-	varinfo.yres = info->y_resolution;
-	varinfo.width = info->width_mm;
-	varinfo.height = info->height_mm;
-	varinfo.bits_per_pixel = info->bits_per_pixel;
-
-	/* Try to set up an ARGB (x8r8g8b8) pixel format. */
-	varinfo.grayscale = 0;
-	varinfo.transp.offset = 24;
-	varinfo.transp.length = 0;
-	varinfo.transp.msb_right = 0;
-	varinfo.red.offset = 16;
-	varinfo.red.length = 8;
-	varinfo.red.msb_right = 0;
-	varinfo.green.offset = 8;
-	varinfo.green.length = 8;
-	varinfo.green.msb_right = 0;
-	varinfo.blue.offset = 0;
-	varinfo.blue.length = 8;
-	varinfo.blue.msb_right = 0;
-
 	/* Set the device's screen information. */
-	if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
+	if (fd > 0 && ioctl(fd, FBIOPUT_VSCREENINFO, &info->varinfo) < 0) {
 		return -1;
 	}
 
@@ -378,8 +418,7 @@ static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
 
 /* Returns an FD for the frame buffer device. */
 static int
-fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
-                        struct fbdev_screeninfo *screen_info)
+fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev)
 {
 	int fd = -1;
 
@@ -393,15 +432,6 @@ fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
 		return -1;
 	}
 
-	/* Grab the screen info. */
-	if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
-		weston_log("Failed to get frame buffer info: %s\n",
-		           strerror(errno));
-
-		close(fd);
-		return -1;
-	}
-
 	return fd;
 }
 
@@ -426,8 +456,8 @@ fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
 	/* Create a pixman image to wrap the memory mapped frame buffer. */
 	output->hw_surface =
 		pixman_image_create_bits(output->fb_info.pixel_format,
-		                         output->fb_info.x_resolution,
-		                         output->fb_info.y_resolution,
+		                         output->fb_info.varinfo.xres,
+		                         output->fb_info.varinfo.yres,
 		                         output->fb,
 		                         output->fb_info.line_length);
 	if (output->hw_surface == NULL) {
@@ -484,18 +514,34 @@ fbdev_output_create(struct fbdev_compositor *compositor,
 
 	output->compositor = compositor;
 	output->device = device;
+	output->base.name = strdup(basename(device));
 
+	fbdev_read_config(compositor, output);
 	/* Create the frame buffer. */
-	fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
+	fb_fd = fbdev_frame_buffer_open(output, device);
 	if (fb_fd < 0) {
 		weston_log("Creating frame buffer failed.\n");
 		goto out_free;
 	}
 
+	/* Set the screen info. */
+	if (fbdev_frame_buffer_set(output, fb_fd, &output->fb_info) < 0) {
+		weston_log("Failed to get frame buffer info: %s\n",
+		           strerror(errno));
+		close(fb_fd);
+		goto out_free;
+	}
+
+	width = output->fb_info.varinfo.xres;
+	height = output->fb_info.varinfo.yres;
+
 	if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
 		weston_log("Mapping frame buffer failed.\n");
+		close(fb_fd);
 		goto out_free;
 	}
+	/* after fbdev_frame_buffer_map the file is closed */
+	fb_fd = -1;
 
 	output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
 	output->base.repaint = fbdev_output_repaint;
@@ -508,8 +554,8 @@ fbdev_output_create(struct fbdev_compositor *compositor,
 	/* only one static mode in list */
 	output->mode.flags =
 		WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-	output->mode.width = output->fb_info.x_resolution;
-	output->mode.height = output->fb_info.y_resolution;
+	output->mode.width = width;
+	output->mode.height = height;
 	output->mode.refresh = output->fb_info.refresh_rate;
 	wl_list_init(&output->base.mode_list);
 	wl_list_insert(&output->base.mode_list, &output->mode.link);
@@ -521,14 +567,11 @@ fbdev_output_create(struct fbdev_compositor *compositor,
 	output->base.model = output->fb_info.id;
 
 	weston_output_init(&output->base, &compositor->base,
-	                   0, 0, output->fb_info.width_mm,
-	                   output->fb_info.height_mm,
-	                   WL_OUTPUT_TRANSFORM_NORMAL,
+	                   0, 0, output->fb_info.varinfo.width,
+	                   output->fb_info.varinfo.height,
+	                   output->base.transform,
 			   1);
 
-	width = output->fb_info.x_resolution;
-	height = output->fb_info.y_resolution;
-
 	pixman_transform_init_identity(&transform);
 	switch (output->base.transform) {
 	default:
@@ -571,7 +614,7 @@ fbdev_output_create(struct fbdev_compositor *compositor,
 		break;
 	}
 
-	bytes_per_pixel = output->fb_info.bits_per_pixel / 8;
+	bytes_per_pixel = output->fb_info.varinfo.bits_per_pixel / 8;
 
 	output->shadow_buf = malloc(width * height * bytes_per_pixel);
 	output->shadow_surface =
@@ -597,7 +640,7 @@ fbdev_output_create(struct fbdev_compositor *compositor,
 
 	wl_list_insert(compositor->base.output_list.prev, &output->base.link);
 
-	weston_log("fbdev output %d×%d px\n",
+	weston_log("fbdev output %dx%d px\n",
 	           output->mode.width, output->mode.height);
 	weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
 	                    output->mode.refresh / 1000);
@@ -614,6 +657,7 @@ out_hw_surface:
 	weston_output_destroy(&output->base);
 	fbdev_frame_buffer_destroy(output);
 out_free:
+	free(output->base.name);
 	free(output);
 
 	return -1;
@@ -649,23 +693,6 @@ fbdev_output_destroy(struct weston_output *base)
 	free(output);
 }
 
-/* strcmp()-style return values. */
-static int
-compare_screen_info (const struct fbdev_screeninfo *a,
-                     const struct fbdev_screeninfo *b)
-{
-	if (a->x_resolution == b->x_resolution &&
-	    a->y_resolution == b->y_resolution &&
-	    a->width_mm == b->width_mm &&
-	    a->height_mm == b->height_mm &&
-	    a->bits_per_pixel == b->bits_per_pixel &&
-	    a->pixel_format == b->pixel_format &&
-	    a->refresh_rate == b->refresh_rate)
-		return 0;
-
-	return 1;
-}
-
 static int
 fbdev_output_reenable(struct fbdev_compositor *compositor,
                       struct weston_output *base)
@@ -677,23 +704,17 @@ fbdev_output_reenable(struct fbdev_compositor *compositor,
 	weston_log("Re-enabling fbdev output.\n");
 
 	/* Create the frame buffer. */
-	fb_fd = fbdev_frame_buffer_open(output, output->device,
-	                                &new_screen_info);
+	fb_fd = fbdev_frame_buffer_open(output, output->device);
 	if (fb_fd < 0) {
 		weston_log("Creating frame buffer failed.\n");
 		goto err;
 	}
 
-	/* Check whether the frame buffer details have changed since we were
-	 * disabled. */
-	if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
-		/* Perform a mode-set to restore the old mode. */
-		if (fbdev_set_screen_info(output, fb_fd,
-		                          &output->fb_info) < 0) {
-			weston_log("Failed to restore mode settings. "
-			           "Attempting to re-open output anyway.\n");
-		}
-
+	/* Perform a mode-set to restore the old mode. */
+	if (fbdev_set_screen_info(output, fb_fd,
+							  &output->fb_info) < 0) {
+		weston_log("Failed to restore mode settings. "
+				   "Attempting to re-open output anyway.\n");
 		/* Remove and re-add the output so that resources depending on
 		 * the frame buffer X/Y resolution (such as the shadow buffer)
 		 * are re-initialised. */
@@ -706,6 +727,7 @@ fbdev_output_reenable(struct fbdev_compositor *compositor,
 	/* Map the device if it has the same details as before. */
 	if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
 		weston_log("Mapping frame buffer failed.\n");
+		close(fb_fd);
 		goto err;
 	}
 
-- 
1.7.9.5



More information about the wayland-devel mailing list