1/*	$NetBSD: modesetting.c,v 1.2 2021/12/18 23:45:44 riastradh Exp $	*/
2
3// SPDX-License-Identifier: MIT
4/* Copyright (C) 2006-2017 Oracle Corporation */
5
6#include <sys/cdefs.h>
7__KERNEL_RCSID(0, "$NetBSD: modesetting.c,v 1.2 2021/12/18 23:45:44 riastradh Exp $");
8
9#include <linux/vbox_err.h>
10#include "vbox_drv.h"
11#include "vboxvideo_guest.h"
12#include "vboxvideo_vbe.h"
13#include "hgsmi_channels.h"
14
15/**
16 * Set a video mode via an HGSMI request.  The views must have been
17 * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
18 * set on the first display then it must be set first using registers.
19 * @ctx:           The context containing the heap to use.
20 * @display:       The screen number.
21 * @origin_x:      The horizontal displacement relative to the first scrn.
22 * @origin_y:      The vertical displacement relative to the first screen.
23 * @start_offset:  The offset of the visible area of the framebuffer
24 *                 relative to the framebuffer start.
25 * @pitch:         The offset in bytes between the starts of two adjecent
26 *                 scan lines in video RAM.
27 * @width:         The mode width.
28 * @height:        The mode height.
29 * @bpp:           The colour depth of the mode.
30 * @flags:         Flags.
31 */
32void hgsmi_process_display_info(struct gen_pool *ctx, u32 display,
33				s32 origin_x, s32 origin_y, u32 start_offset,
34				u32 pitch, u32 width, u32 height,
35				u16 bpp, u16 flags)
36{
37	struct vbva_infoscreen *p;
38
39	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
40			       VBVA_INFO_SCREEN);
41	if (!p)
42		return;
43
44	p->view_index = display;
45	p->origin_x = origin_x;
46	p->origin_y = origin_y;
47	p->start_offset = start_offset;
48	p->line_size = pitch;
49	p->width = width;
50	p->height = height;
51	p->bits_per_pixel = bpp;
52	p->flags = flags;
53
54	hgsmi_buffer_submit(ctx, p);
55	hgsmi_buffer_free(ctx, p);
56}
57
58/**
59 * Report the rectangle relative to which absolute pointer events should be
60 * expressed.  This information remains valid until the next VBVA resize event
61 * for any screen, at which time it is reset to the bounding rectangle of all
62 * virtual screens.
63 * Return: 0 or negative errno value.
64 * @ctx:       The context containing the heap to use.
65 * @origin_x:  Upper left X co-ordinate relative to the first screen.
66 * @origin_y:  Upper left Y co-ordinate relative to the first screen.
67 * @width:     Rectangle width.
68 * @height:    Rectangle height.
69 */
70int hgsmi_update_input_mapping(struct gen_pool *ctx, s32 origin_x, s32 origin_y,
71			       u32 width, u32 height)
72{
73	struct vbva_report_input_mapping *p;
74
75	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
76			       VBVA_REPORT_INPUT_MAPPING);
77	if (!p)
78		return -ENOMEM;
79
80	p->x = origin_x;
81	p->y = origin_y;
82	p->cx = width;
83	p->cy = height;
84
85	hgsmi_buffer_submit(ctx, p);
86	hgsmi_buffer_free(ctx, p);
87
88	return 0;
89}
90
91/**
92 * Get most recent video mode hints.
93 * Return: 0 or negative errno value.
94 * @ctx:      The context containing the heap to use.
95 * @screens:  The number of screens to query hints for, starting at 0.
96 * @hints:    Array of vbva_modehint structures for receiving the hints.
97 */
98int hgsmi_get_mode_hints(struct gen_pool *ctx, unsigned int screens,
99			 struct vbva_modehint *hints)
100{
101	struct vbva_query_mode_hints *p;
102	size_t size;
103
104	if (WARN_ON(!hints))
105		return -EINVAL;
106
107	size = screens * sizeof(struct vbva_modehint);
108	p = hgsmi_buffer_alloc(ctx, sizeof(*p) + size, HGSMI_CH_VBVA,
109			       VBVA_QUERY_MODE_HINTS);
110	if (!p)
111		return -ENOMEM;
112
113	p->hints_queried_count = screens;
114	p->hint_structure_guest_size = sizeof(struct vbva_modehint);
115	p->rc = VERR_NOT_SUPPORTED;
116
117	hgsmi_buffer_submit(ctx, p);
118
119	if (p->rc < 0) {
120		hgsmi_buffer_free(ctx, p);
121		return -EIO;
122	}
123
124	memcpy(hints, ((u8 *)p) + sizeof(struct vbva_query_mode_hints), size);
125	hgsmi_buffer_free(ctx, p);
126
127	return 0;
128}
129