• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2008-2011 Kristian Høgsberg
3  * Copyright © 2011 Intel Corporation
4  * Copyright © 2012 Raspberry Pi Foundation
5  * Copyright © 2013 Philip Withnall
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial
17  * portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  */
28 
29 #include "config.h"
30 
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37 #include <sys/mman.h>
38 #include <sys/types.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <linux/fb.h>
42 #include <linux/input.h>
43 #include <assert.h>
44 
45 #include <libudev.h>
46 
47 #include "shared/helpers.h"
48 #include <libweston/libweston.h>
49 #include <libweston/backend-fbdev.h>
50 #include "launcher-util.h"
51 #include "pixman-renderer.h"
52 #include "libinput-seat.h"
53 #include "presentation-time-server-protocol.h"
54 
55 struct fbdev_backend {
56 	struct weston_backend base;
57 	struct weston_compositor *compositor;
58 	uint32_t prev_state;
59 
60 	struct udev *udev;
61 	struct udev_input input;
62 	uint32_t output_transform;
63 	struct wl_listener session_listener;
64 };
65 
66 struct fbdev_screeninfo {
67 	unsigned int x_resolution; /* pixels, visible area */
68 	unsigned int y_resolution; /* pixels, visible area */
69 	unsigned int width_mm; /* visible screen width in mm */
70 	unsigned int height_mm; /* visible screen height in mm */
71 	unsigned int bits_per_pixel;
72 
73 	size_t buffer_length; /* length of frame buffer memory in bytes */
74 	size_t line_length; /* length of a line in bytes */
75 	char id[16]; /* screen identifier */
76 
77 	pixman_format_code_t pixel_format; /* frame buffer pixel format */
78 	unsigned int refresh_rate; /* Hertz */
79 };
80 
81 struct fbdev_head {
82 	struct weston_head base;
83 
84 	/* Frame buffer details. */
85 	char *device;
86 	struct fbdev_screeninfo fb_info;
87 };
88 
89 struct fbdev_output {
90 	struct fbdev_backend *backend;
91 	struct weston_output base;
92 
93 	struct weston_mode mode;
94 	struct wl_event_source *finish_frame_timer;
95 
96 	/* framebuffer mmap details */
97 	size_t buffer_length;
98 	void *fb;
99 
100 	/* pixman details. */
101 	pixman_image_t *hw_surface;
102 };
103 
104 static const char default_seat[] = "seat0";
105 
106 static inline struct fbdev_head *
to_fbdev_head(struct weston_head * base)107 to_fbdev_head(struct weston_head *base)
108 {
109 	return container_of(base, struct fbdev_head, base);
110 }
111 
112 static inline struct fbdev_output *
to_fbdev_output(struct weston_output * base)113 to_fbdev_output(struct weston_output *base)
114 {
115 	return container_of(base, struct fbdev_output, base);
116 }
117 
118 static inline struct fbdev_backend *
to_fbdev_backend(struct weston_compositor * base)119 to_fbdev_backend(struct weston_compositor *base)
120 {
121 	return container_of(base->backend, struct fbdev_backend, base);
122 }
123 
124 static struct fbdev_head *
fbdev_output_get_head(struct fbdev_output * output)125 fbdev_output_get_head(struct fbdev_output *output)
126 {
127 	if (wl_list_length(&output->base.head_list) != 1)
128 		return NULL;
129 
130 	return container_of(output->base.head_list.next,
131 			    struct fbdev_head, base.output_link);
132 }
133 
134 static int
fbdev_output_start_repaint_loop(struct weston_output * output)135 fbdev_output_start_repaint_loop(struct weston_output *output)
136 {
137 	struct timespec ts;
138 
139 	weston_compositor_read_presentation_clock(output->compositor, &ts);
140 	weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
141 
142 	return 0;
143 }
144 
145 static int
fbdev_output_repaint(struct weston_output * base,pixman_region32_t * damage,void * repaint_data)146 fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage,
147 		     void *repaint_data)
148 {
149 	struct fbdev_output *output = to_fbdev_output(base);
150 	struct weston_compositor *ec = output->base.compositor;
151 
152 	/* Repaint the damaged region onto the back buffer. */
153 	pixman_renderer_output_set_buffer(base, output->hw_surface);
154 	ec->renderer->repaint_output(base, damage);
155 
156 	/* Update the damage region. */
157 	pixman_region32_subtract(&ec->primary_plane.damage,
158 	                         &ec->primary_plane.damage, damage);
159 
160 	/* Schedule the end of the frame. We do not sync this to the frame
161 	 * buffer clock because users who want that should be using the DRM
162 	 * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
163 	 * panning, which is broken in most kernel drivers.
164 	 *
165 	 * Finish the frame synchronised to the specified refresh rate. The
166 	 * refresh rate is given in mHz and the interval in ms. */
167 	wl_event_source_timer_update(output->finish_frame_timer,
168 	                             1000000 / output->mode.refresh);
169 
170 	return 0;
171 }
172 
173 static int
finish_frame_handler(void * data)174 finish_frame_handler(void *data)
175 {
176 	struct fbdev_output *output = data;
177 	struct timespec ts;
178 
179 	weston_compositor_read_presentation_clock(output->base.compositor, &ts);
180 	weston_output_finish_frame(&output->base, &ts, 0);
181 
182 	return 1;
183 }
184 
185 static pixman_format_code_t
calculate_pixman_format(struct fb_var_screeninfo * vinfo,struct fb_fix_screeninfo * finfo)186 calculate_pixman_format(struct fb_var_screeninfo *vinfo,
187                         struct fb_fix_screeninfo *finfo)
188 {
189 	/* Calculate the pixman format supported by the frame buffer from the
190 	 * buffer's metadata. Return 0 if no known pixman format is supported
191 	 * (since this has depth 0 it's guaranteed to not conflict with any
192 	 * actual pixman format).
193 	 *
194 	 * Documentation on the vinfo and finfo structures:
195 	 *    http://www.mjmwired.net/kernel/Documentation/fb/api.txt
196 	 *
197 	 * TODO: Try a bit harder to support other formats, including setting
198 	 * the preferred format in the hardware. */
199 	int type;
200 
201 	weston_log("Calculating pixman format from:\n"
202 	           STAMP_SPACE " - type: %i (aux: %i)\n"
203 	           STAMP_SPACE " - visual: %i\n"
204 	           STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
205 	           STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
206 	           STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
207 	           STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
208 	           STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
209 	           finfo->type, finfo->type_aux, finfo->visual,
210 	           vinfo->bits_per_pixel, vinfo->grayscale,
211 	           vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
212 	           vinfo->green.offset, vinfo->green.length,
213 	           vinfo->green.msb_right,
214 	           vinfo->blue.offset, vinfo->blue.length,
215 	           vinfo->blue.msb_right,
216 	           vinfo->transp.offset, vinfo->transp.length,
217 	           vinfo->transp.msb_right);
218 
219 	/* We only handle packed formats at the moment. */
220 	if (finfo->type != FB_TYPE_PACKED_PIXELS)
221 		return 0;
222 
223 	/* We only handle true-colour frame buffers at the moment. */
224 	switch(finfo->visual) {
225 		case FB_VISUAL_TRUECOLOR:
226 		case FB_VISUAL_DIRECTCOLOR:
227 			if (vinfo->grayscale != 0)
228 				return 0;
229 		break;
230 		default:
231 			return 0;
232 	}
233 
234 	/* We only support formats with MSBs on the left. */
235 	if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
236 	    vinfo->blue.msb_right != 0)
237 		return 0;
238 
239 	/* Work out the format type from the offsets. We only support RGBA, ARGB
240 	 * and ABGR at the moment. */
241 	type = PIXMAN_TYPE_OTHER;
242 
243 	if ((vinfo->transp.offset >= vinfo->red.offset ||
244 	     vinfo->transp.length == 0) &&
245 	    vinfo->red.offset >= vinfo->green.offset &&
246 	    vinfo->green.offset >= vinfo->blue.offset)
247 		type = PIXMAN_TYPE_ARGB;
248 	else if (vinfo->red.offset >= vinfo->green.offset &&
249 	         vinfo->green.offset >= vinfo->blue.offset &&
250 	         vinfo->blue.offset >= vinfo->transp.offset)
251 		type = PIXMAN_TYPE_RGBA;
252 	else if (vinfo->transp.offset >= vinfo->blue.offset &&
253 	         vinfo->blue.offset >= vinfo->green.offset &&
254 	         vinfo->green.offset >= vinfo->red.offset)
255 		type = PIXMAN_TYPE_ABGR;
256 
257 	if (type == PIXMAN_TYPE_OTHER)
258 		return 0;
259 
260 	/* Build the format. */
261 	return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
262 	                     vinfo->transp.length,
263 	                     vinfo->red.length,
264 	                     vinfo->green.length,
265 	                     vinfo->blue.length);
266 }
267 
268 static int
calculate_refresh_rate(struct fb_var_screeninfo * vinfo)269 calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
270 {
271 	uint64_t quot;
272 
273 	/* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
274 	quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
275 	quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
276 	quot *= vinfo->pixclock;
277 
278 	if (quot > 0) {
279 		uint64_t refresh_rate;
280 
281 		refresh_rate = 1000000000000000LLU / quot;
282 		if (refresh_rate > 200000)
283 			refresh_rate = 200000; /* cap at 200 Hz */
284 
285 		if (refresh_rate >= 1000) /* at least 1 Hz */
286 			return refresh_rate;
287 	}
288 
289 	return 60 * 1000; /* default to 60 Hz */
290 }
291 
292 static int
fbdev_query_screen_info(int fd,struct fbdev_screeninfo * info)293 fbdev_query_screen_info(int fd, struct fbdev_screeninfo *info)
294 {
295 	struct fb_var_screeninfo varinfo;
296 	struct fb_fix_screeninfo fixinfo;
297 
298 	/* Probe the device for screen information. */
299 	if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
300 	    ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
301 		return -1;
302 	}
303 
304 	/* Store the pertinent data. */
305 	info->x_resolution = varinfo.xres;
306 	info->y_resolution = varinfo.yres;
307 	info->width_mm = varinfo.width;
308 	info->height_mm = varinfo.height;
309 	info->bits_per_pixel = varinfo.bits_per_pixel;
310 
311 	info->buffer_length = fixinfo.smem_len;
312 	info->line_length = fixinfo.line_length;
313 	strncpy(info->id, fixinfo.id, sizeof(info->id));
314 	info->id[sizeof(info->id)-1] = '\0';
315 
316 	info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
317 	info->refresh_rate = calculate_refresh_rate(&varinfo);
318 
319 	if (info->pixel_format == 0) {
320 		weston_log("Frame buffer uses an unsupported format.\n");
321 		return -1;
322 	}
323 
324 	return 1;
325 }
326 
327 static int
fbdev_set_screen_info(int fd,struct fbdev_screeninfo * info)328 fbdev_set_screen_info(int fd, struct fbdev_screeninfo *info)
329 {
330 	struct fb_var_screeninfo varinfo;
331 
332 	/* Grab the current screen information. */
333 	if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
334 		return -1;
335 	}
336 
337 	/* Update the information. */
338 	varinfo.xres = info->x_resolution;
339 	varinfo.yres = info->y_resolution;
340 	varinfo.width = info->width_mm;
341 	varinfo.height = info->height_mm;
342 	varinfo.bits_per_pixel = info->bits_per_pixel;
343 
344 	/* Try to set up an ARGB (x8r8g8b8) pixel format. */
345 	varinfo.grayscale = 0;
346 	varinfo.transp.offset = 24;
347 	varinfo.transp.length = 0;
348 	varinfo.transp.msb_right = 0;
349 	varinfo.red.offset = 16;
350 	varinfo.red.length = 8;
351 	varinfo.red.msb_right = 0;
352 	varinfo.green.offset = 8;
353 	varinfo.green.length = 8;
354 	varinfo.green.msb_right = 0;
355 	varinfo.blue.offset = 0;
356 	varinfo.blue.length = 8;
357 	varinfo.blue.msb_right = 0;
358 
359 	/* Set the device's screen information. */
360 	if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
361 		return -1;
362 	}
363 
364 	return 1;
365 }
366 
367 static int
fbdev_wakeup_screen(int fd,struct fbdev_screeninfo * info)368 fbdev_wakeup_screen(int fd, struct fbdev_screeninfo *info)
369 {
370 	struct fb_var_screeninfo varinfo;
371 
372 	/* Grab the current screen information. */
373 	if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
374 		return -1;
375 	}
376 
377 	/* force the framebuffer to wake up */
378 	varinfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
379 
380 	/* Set the device's screen information. */
381 	if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
382 		return -1;
383 	}
384 
385 	return 1;
386 }
387 
388 /* Returns an FD for the frame buffer device. */
389 static int
fbdev_frame_buffer_open(const char * fb_dev,struct fbdev_screeninfo * screen_info)390 fbdev_frame_buffer_open(const char *fb_dev,
391 			struct fbdev_screeninfo *screen_info)
392 {
393 	int fd = -1;
394 
395 	weston_log("Opening fbdev frame buffer.\n");
396 
397 	/* Open the frame buffer device. */
398 	fd = open(fb_dev, O_RDWR | O_CLOEXEC);
399 	if (fd < 0) {
400 		weston_log("Failed to open frame buffer device ‘%s’: %s\n",
401 		           fb_dev, strerror(errno));
402 		return -1;
403 	}
404 
405 	/* Grab the screen info. */
406 	if (fbdev_query_screen_info(fd, screen_info) < 0) {
407 		weston_log("Failed to get frame buffer info: %s\n",
408 		           strerror(errno));
409 
410 		close(fd);
411 		return -1;
412 	}
413 
414 	/* Attempt to wake up the framebuffer device, needed for secondary
415 	 * framebuffer devices */
416 	if (fbdev_wakeup_screen(fd, screen_info) < 0) {
417 		weston_log("Failed to activate framebuffer display. "
418 		           "Attempting to open output anyway.\n");
419 	}
420 
421 
422 	return fd;
423 }
424 
425 /* Closes the FD on success or failure. */
426 static int
fbdev_frame_buffer_map(struct fbdev_output * output,int fd)427 fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
428 {
429 	struct fbdev_head *head;
430 	int retval = -1;
431 
432 	head = fbdev_output_get_head(output);
433 
434 	weston_log("Mapping fbdev frame buffer.\n");
435 
436 	/* Map the frame buffer. Write-only mode, since we don't want to read
437 	 * anything back (because it's slow). */
438 	output->buffer_length = head->fb_info.buffer_length;
439 	output->fb = mmap(NULL, output->buffer_length,
440 	                  PROT_WRITE, MAP_SHARED, fd, 0);
441 	if (output->fb == MAP_FAILED) {
442 		weston_log("Failed to mmap frame buffer: %s\n",
443 		           strerror(errno));
444 		output->fb = NULL;
445 		goto out_close;
446 	}
447 
448 	/* Create a pixman image to wrap the memory mapped frame buffer. */
449 	output->hw_surface =
450 		pixman_image_create_bits(head->fb_info.pixel_format,
451 		                         head->fb_info.x_resolution,
452 		                         head->fb_info.y_resolution,
453 		                         output->fb,
454 		                         head->fb_info.line_length);
455 	if (output->hw_surface == NULL) {
456 		weston_log("Failed to create surface for frame buffer.\n");
457 		goto out_unmap;
458 	}
459 
460 	/* Success! */
461 	retval = 0;
462 
463 out_unmap:
464 	if (retval != 0 && output->fb != NULL) {
465 		munmap(output->fb, output->buffer_length);
466 		output->fb = NULL;
467 	}
468 
469 out_close:
470 	if (fd >= 0)
471 		close(fd);
472 
473 	return retval;
474 }
475 
476 static void
fbdev_frame_buffer_unmap(struct fbdev_output * output)477 fbdev_frame_buffer_unmap(struct fbdev_output *output)
478 {
479 	if (!output->fb) {
480 		assert(!output->hw_surface);
481 		return;
482 	}
483 
484 	weston_log("Unmapping fbdev frame buffer.\n");
485 
486 	if (output->hw_surface)
487 		pixman_image_unref(output->hw_surface);
488 	output->hw_surface = NULL;
489 
490 	if (munmap(output->fb, output->buffer_length) < 0)
491 		weston_log("Failed to munmap frame buffer: %s\n",
492 		           strerror(errno));
493 
494 	output->fb = NULL;
495 }
496 
497 
498 static int
fbdev_output_attach_head(struct weston_output * output_base,struct weston_head * head_base)499 fbdev_output_attach_head(struct weston_output *output_base,
500 			 struct weston_head *head_base)
501 {
502 	struct fbdev_output *output = to_fbdev_output(output_base);
503 	struct fbdev_head *head = to_fbdev_head(head_base);
504 
505 	/* Clones not supported. */
506 	if (!wl_list_empty(&output->base.head_list))
507 		return -1;
508 
509 	/* only one static mode in list */
510 	output->mode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
511 	output->mode.width = head->fb_info.x_resolution;
512 	output->mode.height = head->fb_info.y_resolution;
513 	output->mode.refresh = head->fb_info.refresh_rate;
514 	wl_list_init(&output->base.mode_list);
515 	wl_list_insert(&output->base.mode_list, &output->mode.link);
516 	output->base.current_mode = &output->mode;
517 
518 	return 0;
519 }
520 
521 static void fbdev_output_destroy(struct weston_output *base);
522 
523 static int
fbdev_output_enable(struct weston_output * base)524 fbdev_output_enable(struct weston_output *base)
525 {
526 	struct fbdev_output *output = to_fbdev_output(base);
527 	struct fbdev_backend *backend = to_fbdev_backend(base->compositor);
528 	struct fbdev_head *head;
529 	int fb_fd;
530 	struct wl_event_loop *loop;
531 	const struct pixman_renderer_output_options options = {
532 		.use_shadow = true,
533 	};
534 
535 	head = fbdev_output_get_head(output);
536 
537 	/* Create the frame buffer. */
538 	fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
539 	if (fb_fd < 0) {
540 		weston_log("Creating frame buffer failed.\n");
541 		return -1;
542 	}
543 
544 	if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
545 		weston_log("Mapping frame buffer failed.\n");
546 		return -1;
547 	}
548 
549 	output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
550 	output->base.repaint = fbdev_output_repaint;
551 
552 	if (pixman_renderer_output_create(&output->base, &options) < 0)
553 		goto out_hw_surface;
554 
555 	loop = wl_display_get_event_loop(backend->compositor->wl_display);
556 	output->finish_frame_timer =
557 		wl_event_loop_add_timer(loop, finish_frame_handler, output);
558 
559 	weston_log("fbdev output %d×%d px\n",
560 	           output->mode.width, output->mode.height);
561 	weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
562 	                    output->mode.refresh / 1000);
563 
564 	return 0;
565 
566 out_hw_surface:
567 	fbdev_frame_buffer_unmap(output);
568 
569 	return -1;
570 }
571 
572 static int
fbdev_output_disable(struct weston_output * base)573 fbdev_output_disable(struct weston_output *base)
574 {
575 	struct fbdev_output *output = to_fbdev_output(base);
576 
577 	if (!base->enabled)
578 		return 0;
579 
580 	wl_event_source_remove(output->finish_frame_timer);
581 	output->finish_frame_timer = NULL;
582 
583 	pixman_renderer_output_destroy(&output->base);
584 	fbdev_frame_buffer_unmap(output);
585 
586 	return 0;
587 }
588 
589 static struct fbdev_head *
fbdev_head_create(struct fbdev_backend * backend,const char * device)590 fbdev_head_create(struct fbdev_backend *backend, const char *device)
591 {
592 	struct fbdev_head *head;
593 	int fb_fd;
594 
595 	head = zalloc(sizeof *head);
596 	if (!head)
597 		return NULL;
598 
599 	head->device = strdup(device);
600 
601 	/* Create the frame buffer. */
602 	fb_fd = fbdev_frame_buffer_open(head->device, &head->fb_info);
603 	if (fb_fd < 0) {
604 		weston_log("Creating frame buffer head failed.\n");
605 		goto out_free;
606 	}
607 	close(fb_fd);
608 
609 	weston_head_init(&head->base, "fbdev");
610 	weston_head_set_connection_status(&head->base, true);
611 	weston_head_set_monitor_strings(&head->base, "unknown",
612 					head->fb_info.id, NULL);
613 	weston_head_set_subpixel(&head->base, WL_OUTPUT_SUBPIXEL_UNKNOWN);
614 	weston_head_set_physical_size(&head->base, head->fb_info.width_mm,
615 				      head->fb_info.height_mm);
616 
617 	weston_compositor_add_head(backend->compositor, &head->base);
618 
619 	weston_log("Created head '%s' for device %s (%s)\n",
620 		   head->base.name, head->device, head->base.model);
621 
622 	return head;
623 
624 out_free:
625 	free(head->device);
626 	free(head);
627 
628 	return NULL;
629 }
630 
631 static void
fbdev_head_destroy(struct fbdev_head * head)632 fbdev_head_destroy(struct fbdev_head *head)
633 {
634 	weston_head_release(&head->base);
635 	free(head->device);
636 	free(head);
637 }
638 
639 static struct weston_output *
fbdev_output_create(struct weston_compositor * compositor,const char * name)640 fbdev_output_create(struct weston_compositor *compositor,
641                     const char *name)
642 {
643 	struct fbdev_output *output;
644 
645 	weston_log("Creating fbdev output.\n");
646 
647 	output = zalloc(sizeof *output);
648 	if (output == NULL)
649 		return NULL;
650 
651 	output->backend = to_fbdev_backend(compositor);
652 
653 	weston_output_init(&output->base, compositor, name);
654 
655 	output->base.destroy = fbdev_output_destroy;
656 	output->base.disable = fbdev_output_disable;
657 	output->base.enable = fbdev_output_enable;
658 	output->base.attach_head = fbdev_output_attach_head;
659 
660 	weston_compositor_add_pending_output(&output->base, compositor);
661 
662 	return &output->base;
663 }
664 
665 static void
fbdev_output_destroy(struct weston_output * base)666 fbdev_output_destroy(struct weston_output *base)
667 {
668 	struct fbdev_output *output = to_fbdev_output(base);
669 
670 	weston_log("Destroying fbdev output.\n");
671 
672 	fbdev_output_disable(base);
673 
674 	/* Remove the output. */
675 	weston_output_release(&output->base);
676 
677 	free(output);
678 }
679 
680 /* strcmp()-style return values. */
681 static int
compare_screen_info(const struct fbdev_screeninfo * a,const struct fbdev_screeninfo * b)682 compare_screen_info (const struct fbdev_screeninfo *a,
683                      const struct fbdev_screeninfo *b)
684 {
685 	if (a->x_resolution == b->x_resolution &&
686 	    a->y_resolution == b->y_resolution &&
687 	    a->width_mm == b->width_mm &&
688 	    a->height_mm == b->height_mm &&
689 	    a->bits_per_pixel == b->bits_per_pixel &&
690 	    a->pixel_format == b->pixel_format &&
691 	    a->refresh_rate == b->refresh_rate)
692 		return 0;
693 
694 	return 1;
695 }
696 
697 static int
fbdev_output_reenable(struct fbdev_backend * backend,struct weston_output * base)698 fbdev_output_reenable(struct fbdev_backend *backend,
699                       struct weston_output *base)
700 {
701 	struct fbdev_output *output = to_fbdev_output(base);
702 	struct fbdev_head *head;
703 	struct fbdev_screeninfo new_screen_info;
704 	int fb_fd;
705 
706 	head = fbdev_output_get_head(output);
707 
708 	weston_log("Re-enabling fbdev output.\n");
709 	assert(output->base.enabled);
710 
711 	/* Create the frame buffer. */
712 	fb_fd = fbdev_frame_buffer_open(head->device, &new_screen_info);
713 	if (fb_fd < 0) {
714 		weston_log("Creating frame buffer failed.\n");
715 		return -1;
716 	}
717 
718 	/* Check whether the frame buffer details have changed since we were
719 	 * disabled. */
720 	if (compare_screen_info(&head->fb_info, &new_screen_info) != 0) {
721 		/* Perform a mode-set to restore the old mode. */
722 		if (fbdev_set_screen_info(fb_fd, &head->fb_info) < 0) {
723 			weston_log("Failed to restore mode settings. "
724 			           "Attempting to re-open output anyway.\n");
725 		}
726 
727 		close(fb_fd);
728 
729 		/* Disable and enable the output so that resources depending on
730 		 * the frame buffer X/Y resolution (such as the shadow buffer)
731 		 * are re-initialised. */
732 		fbdev_output_disable(&output->base);
733 		return fbdev_output_enable(&output->base);
734 	}
735 
736 	/* Map the device if it has the same details as before. */
737 	if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
738 		weston_log("Mapping frame buffer failed.\n");
739 		return -1;
740 	}
741 
742 	return 0;
743 }
744 
745 static void
fbdev_backend_destroy(struct weston_compositor * base)746 fbdev_backend_destroy(struct weston_compositor *base)
747 {
748 	struct fbdev_backend *backend = to_fbdev_backend(base);
749 	struct weston_head *head, *next;
750 
751 	udev_input_destroy(&backend->input);
752 
753 	/* Destroy the output. */
754 	weston_compositor_shutdown(base);
755 
756 	wl_list_for_each_safe(head, next, &base->head_list, compositor_link)
757 		fbdev_head_destroy(to_fbdev_head(head));
758 
759 	/* Chain up. */
760 	weston_launcher_destroy(base->launcher);
761 
762 	udev_unref(backend->udev);
763 
764 	free(backend);
765 }
766 
767 static void
session_notify(struct wl_listener * listener,void * data)768 session_notify(struct wl_listener *listener, void *data)
769 {
770 	struct weston_compositor *compositor = data;
771 	struct fbdev_backend *backend = to_fbdev_backend(compositor);
772 	struct weston_output *output;
773 
774 	if (compositor->session_active) {
775 		weston_log("entering VT\n");
776 		compositor->state = backend->prev_state;
777 
778 		wl_list_for_each(output, &compositor->output_list, link) {
779 			fbdev_output_reenable(backend, output);
780 		}
781 
782 		weston_compositor_damage_all(compositor);
783 
784 		udev_input_enable(&backend->input);
785 	} else {
786 		weston_log("leaving VT\n");
787 		udev_input_disable(&backend->input);
788 
789 		wl_list_for_each(output, &compositor->output_list, link) {
790 			fbdev_frame_buffer_unmap(to_fbdev_output(output));
791 		}
792 
793 		backend->prev_state = compositor->state;
794 		weston_compositor_offscreen(compositor);
795 
796 		/* If we have a repaint scheduled (from the idle handler), make
797 		 * sure we cancel that so we don't try to pageflip when we're
798 		 * vt switched away.  The OFFSCREEN state will prevent
799 		 * further attempts at repainting.  When we switch
800 		 * back, we schedule a repaint, which will process
801 		 * pending frame callbacks. */
802 
803 		wl_list_for_each(output,
804 				 &compositor->output_list, link) {
805 			output->repaint_needed = false;
806 		}
807 	}
808 }
809 
810 static char *
find_framebuffer_device(struct fbdev_backend * b,const char * seat)811 find_framebuffer_device(struct fbdev_backend *b, const char *seat)
812 {
813 	struct udev_enumerate *e;
814 	struct udev_list_entry *entry;
815 	const char *path, *device_seat, *id;
816 	char *fb_device_path = NULL;
817 	struct udev_device *device, *fb_device, *pci;
818 
819 	e = udev_enumerate_new(b->udev);
820 	udev_enumerate_add_match_subsystem(e, "graphics");
821 	udev_enumerate_add_match_sysname(e, "fb[0-9]*");
822 
823 	udev_enumerate_scan_devices(e);
824 	fb_device = NULL;
825 	udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
826 		bool is_boot_vga = false;
827 
828 		path = udev_list_entry_get_name(entry);
829 		device = udev_device_new_from_syspath(b->udev, path);
830 		if (!device)
831 			continue;
832 		device_seat = udev_device_get_property_value(device, "ID_SEAT");
833 		if (!device_seat)
834 			device_seat = default_seat;
835 		if (strcmp(device_seat, seat)) {
836 			udev_device_unref(device);
837 			continue;
838 		}
839 
840 		pci = udev_device_get_parent_with_subsystem_devtype(device,
841 								"pci", NULL);
842 		if (pci) {
843 			id = udev_device_get_sysattr_value(pci, "boot_vga");
844 			if (id && !strcmp(id, "1"))
845 				is_boot_vga = true;
846 		}
847 
848 		/* If a framebuffer device was found, and this device isn't
849 		 * the boot-VGA device, don't use it. */
850 		if (!is_boot_vga && fb_device) {
851 			udev_device_unref(device);
852 			continue;
853 		}
854 
855 		/* There can only be one boot_vga device. Try to use it
856 		 * at all costs. */
857 		if (is_boot_vga) {
858 			if (fb_device)
859 				udev_device_unref(fb_device);
860 			fb_device = device;
861 			break;
862 		}
863 
864 		/* Per the (!is_boot_vga && fb_device) test above, only
865 		 * trump existing saved devices with boot-VGA devices, so if
866 		 * the test ends up here, this must be the first device seen. */
867 		assert(!fb_device);
868 		fb_device = device;
869 	}
870 
871 	udev_enumerate_unref(e);
872 
873 	if (fb_device) {
874 		fb_device_path = strdup(udev_device_get_devnode(fb_device));
875 		udev_device_unref(fb_device);
876 	}
877 
878 // OHOS
879 //	return fb_device_path;
880 	weston_log("find_framebuffer_device %s", fb_device_path);
881 	return strdup("/dev/graphics/fb0");
882 }
883 
884 static struct fbdev_backend *
fbdev_backend_create(struct weston_compositor * compositor,struct weston_fbdev_backend_config * param)885 fbdev_backend_create(struct weston_compositor *compositor,
886                      struct weston_fbdev_backend_config *param)
887 {
888 	struct fbdev_backend *backend;
889 	const char *seat_id = default_seat;
890 	const char *session_seat;
891 
892 	session_seat = getenv("XDG_SEAT");
893 	if (session_seat)
894 		seat_id = session_seat;
895 	if (param->seat_id)
896 		seat_id = param->seat_id;
897 
898 	weston_log("initializing fbdev backend\n");
899 
900 	backend = zalloc(sizeof *backend);
901 	if (backend == NULL)
902 		return NULL;
903 
904 	backend->compositor = compositor;
905 	compositor->backend = &backend->base;
906 	if (weston_compositor_set_presentation_clock_software(
907 							compositor) < 0)
908 		goto out_compositor;
909 
910 	backend->udev = udev_new();
911 	if (backend->udev == NULL) {
912 		weston_log("Failed to initialize udev context.\n");
913 		goto out_compositor;
914 	}
915 
916 	if (!param->device)
917 		param->device = find_framebuffer_device(backend, seat_id);
918 	if (!param->device) {
919 		weston_log("fatal: no framebuffer devices detected.\n");
920 		goto out_udev;
921 	}
922 
923 	/* Set up the TTY. */
924 	backend->session_listener.notify = session_notify;
925 	wl_signal_add(&compositor->session_signal,
926 		      &backend->session_listener);
927 	compositor->launcher =
928 		weston_launcher_connect(compositor, param->tty, seat_id, false);
929 	if (!compositor->launcher) {
930 		weston_log("fatal: fbdev backend should be run using "
931 			   "weston-launch binary, or your system should "
932 			   "provide the logind D-Bus API.\n");
933 		goto out_udev;
934 	}
935 
936 	backend->base.destroy = fbdev_backend_destroy;
937 	backend->base.create_output = fbdev_output_create;
938 
939 	backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
940 
941 	weston_setup_vt_switch_bindings(compositor);
942 
943 	if (pixman_renderer_init(compositor) < 0)
944 		goto out_launcher;
945 
946 	if (!fbdev_head_create(backend, param->device))
947 		goto out_launcher;
948 
949 	free(param->device);
950 
951 	udev_input_init(&backend->input, compositor, backend->udev,
952 			seat_id, param->configure_device);
953 
954 	return backend;
955 
956 out_launcher:
957 	free(param->device);
958 	weston_launcher_destroy(compositor->launcher);
959 
960 out_udev:
961 	udev_unref(backend->udev);
962 
963 out_compositor:
964 	weston_compositor_shutdown(compositor);
965 	free(backend);
966 
967 	return NULL;
968 }
969 
970 static void
config_init_to_defaults(struct weston_fbdev_backend_config * config)971 config_init_to_defaults(struct weston_fbdev_backend_config *config)
972 {
973 	config->tty = 0; /* default to current tty */
974 	config->device = NULL;
975 	config->seat_id = NULL;
976 }
977 
978 WL_EXPORT int
weston_backend_init(struct weston_compositor * compositor,struct weston_backend_config * config_base)979 weston_backend_init(struct weston_compositor *compositor,
980 		    struct weston_backend_config *config_base)
981 {
982 	struct fbdev_backend *b;
983 	struct weston_fbdev_backend_config config = {{ 0, }};
984 
985 	if (config_base == NULL ||
986 	    config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
987 	    config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
988 		weston_log("fbdev backend config structure is invalid\n");
989 		return -1;
990 	}
991 
992 	config_init_to_defaults(&config);
993 	memcpy(&config, config_base, config_base->struct_size);
994 
995 	b = fbdev_backend_create(compositor, &config);
996 	if (b == NULL)
997 		return -1;
998 	return 0;
999 }
1000